From 92c51e075e8bc9c2ace8487bfc42f23389d09b73 Mon Sep 17 00:00:00 2001 From: Michael Kifer Date: Fri, 20 Sep 1996 01:10:05 +0000 Subject: [PATCH] *** empty log message *** --- lisp/ediff-diff.el | 63 ++++-- lisp/ediff-hook.el | 2 +- lisp/ediff-init.el | 372 +++++++++++++++++++------------ lisp/ediff-merg.el | 6 + lisp/ediff-mult.el | 282 +++++++++++++++--------- lisp/ediff-ptch.el | 132 ++++++++--- lisp/ediff-util.el | 412 +++++++++++++++++++---------------- lisp/ediff-vers.el | 28 +-- lisp/ediff-wind.el | 5 +- lisp/ediff.el | 96 +++++--- lisp/emulation/viper-util.el | 6 +- lisp/emulation/viper.el | 15 +- 12 files changed, 877 insertions(+), 542 deletions(-) diff --git a/lisp/ediff-diff.el b/lisp/ediff-diff.el index 8f714318f1..31e126c229 100644 --- a/lisp/ediff-diff.el +++ b/lisp/ediff-diff.el @@ -140,31 +140,45 @@ one optional arguments, diff-number to refine.") ;; Run the diff program on FILE1 and FILE2 and put the output in DIFF-BUFFER ;; Return the size of DIFF-BUFFER (defun ediff-make-diff2-buffer (diff-buffer file1 file2) - (cond ((< (ediff-file-size file1) 0) - (message "Can't diff remote files: %s" - (ediff-abbreviate-file-name file1)) - (sit-for 2) - ;; 1 is an error exit code - 1) - ((< (ediff-file-size file2) 0) - (message "Can't diff remote file: %s" - (ediff-abbreviate-file-name file2)) - (sit-for 2) - (message "") - ;; 1 is an error exit code - 1) - (t (message "Computing differences between %s and %s ..." - (file-name-nondirectory file1) - (file-name-nondirectory file2)) - ;; this erases the diff buffer automatically - (ediff-exec-process ediff-diff-program - diff-buffer - 'synchronize - ediff-diff-options file1 file2) - ;;(message "Computing differences ... done") + (let ((file1-size (ediff-file-size file1)) + (file2-size (ediff-file-size file2))) + (cond ((not (numberp file1-size)) + (message "Can't find file: %s" + (ediff-abbreviate-file-name file1)) + (sit-for 2) + ;; 1 is an error exit code + 1) + ((not (numberp file2-size)) + (message "Can't find file: %s" + (ediff-abbreviate-file-name file2)) + (sit-for 2) + ;; 1 is an error exit code + 1) + ((< file1-size 0) + (message "Can't diff remote files: %s" + (ediff-abbreviate-file-name file1)) + (sit-for 2) + ;; 1 is an error exit code + 1) + ((< file2-size 0) + (message "Can't diff remote file: %s" + (ediff-abbreviate-file-name file2)) + (sit-for 2) (message "") - (ediff-eval-in-buffer diff-buffer - (buffer-size))))) + ;; 1 is an error exit code + 1) + (t (message "Computing differences between %s and %s ..." + (file-name-nondirectory file1) + (file-name-nondirectory file2)) + ;; this erases the diff buffer automatically + (ediff-exec-process ediff-diff-program + diff-buffer + 'synchronize + ediff-diff-options file1 file2) + ;;(message "Computing differences ... done") + (message "") + (ediff-eval-in-buffer diff-buffer + (buffer-size)))))) @@ -1187,6 +1201,7 @@ argument to `skip-chars-forward'." ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-diff) diff --git a/lisp/ediff-hook.el b/lisp/ediff-hook.el index 4b20d083b1..0b9dc1fb61 100644 --- a/lisp/ediff-hook.el +++ b/lisp/ediff-hook.el @@ -299,7 +299,7 @@ ;; misc (autoload 'ediff-show-registry - "ediff-meta" + "ediff-mult" "Display the registry of active Ediff sessions." t) (autoload 'ediff-documentation diff --git a/lisp/ediff-init.el b/lisp/ediff-init.el index 9eadd0b855..f6aa724ee4 100644 --- a/lisp/ediff-init.el +++ b/lisp/ediff-init.el @@ -192,10 +192,6 @@ that Ediff doesn't know about.") (error ediff-KILLED-VITAL-BUFFER)) )))) -(put 'ediff-eval-in-buffer 'lisp-indent-function 1) -(put 'ediff-eval-in-buffer 'lisp-indent-hook 1) -(put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) - (defsubst ediff-multiframe-setup-p () (and (ediff-window-display-p) ediff-multiframe)) @@ -286,6 +282,15 @@ that Ediff doesn't know about.") ediff-merge-directory-revisions-with-ancestor ;; add more here ))) +(defsubst ediff-merge-metajob (&optional metajob) + (memq (or metajob ediff-metajob-name) + '(ediff-merge-directories + ediff-merge-directories-with-ancestor + ediff-merge-directory-revisions + ediff-merge-directory-revisions-with-ancestor + ediff-merge-filegroups-with-ancestor + ;; add more here + ))) (defsubst ediff-metajob3 (&optional metajob) (memq (or metajob ediff-metajob-name) @@ -349,126 +354,11 @@ set local variables that determine how the display looks like.") "*Hooks to run on exiting Ediff but before killing the control buffer. This is a place to do various cleanups, such as deleting the variant buffers. Ediff provides a function, `ediff-janitor', as one such possible hook.") +(defvar ediff-quit-merge-hook 'ediff-maybe-save-and-delete-merge + "*Hooks to run before quitting a merge job. +The most common use is to save and delete the merge buffer.") -;; Help messages - -(defconst ediff-long-help-message-head - " Moving around | Toggling features | Manipulations -=====================|===========================|=============================" - "The head of the full help message.") -(defconst ediff-long-help-message-tail - "=====================|===========================|============================= - R -show registry | | M -show session group - D -diff output | E -browse Ediff manual| G -send bug report - i -status info | ? -help off | z/q -suspend/quit -------------------------------------------------------------------------------- -X,Y (x,y) on the left are meta-symbols for the keys A,B,C (a,b,c). -X,Y on the right are meta-symbols for buffers A,B,C. -A,B,C on the right denote the working buffers A,B,C, respectively." - "The tail of the full-help message.") - -(defconst ediff-long-help-message-compare3 - " -p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y -n,SPC -next diff | h -hiliting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| | ! -update diff regions - C-l -recenter | ## -ignore whitespace | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - -scroll lt/rt | X -read-only in buf X | wd -save diff output - | m -wide display | ~ -rotate buffers -" - "Help message usually used for 3-way comparison. -Normally, not a user option. See `ediff-help-message' for details.") - -(defconst ediff-long-help-message-compare2 - " -p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A -n,SPC -next diff | h -hiliting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| | ! -update diff regions - C-l -recenter | ## -ignore whitespace | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | -" - "Help message usually used for 2-way comparison. -Normally, not a user option. See `ediff-help-message' for details.") - -(defconst ediff-long-help-message-narrow2 - " -p,DEL -previous diff | | -vert/horiz split |a/b -copy A/B's region to B/A -n,SPC -next diff | h -hiliting | rx -restore buf X's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| % -narrow/widen buffs | ! -update diff regions - C-l -recenter | ## -ignore whitespace | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | -" - "Help message when comparing windows or regions line-by-line. -Normally, not a user option. See `ediff-help-message' for details.") - -(defconst ediff-long-help-message-word-mode - " -p,DEL -previous diff | | -vert/horiz split | xy -copy buf X's region to Y -n,SPC -next diff | h -hiliting | rx -restore buf X's old diff - j -jump to diff | | - gx -goto X's point| % -narrow/widen buffs | ! -recompute diffs - C-l -recenter | | - v/V -scroll up/dn | #f/#h -focus/hide regions | wx -save buf X - -scroll lt/rt | X -read-only in buf X | wd -save diff output - ~ -swap variants | m -wide display | -" - "Help message when comparing windows or regions word-by-word. -Normally, not a user option. See `ediff-help-message' for details.") - -(defconst ediff-long-help-message-merge - " -p,DEL -previous diff | | -vert/horiz split | x -copy buf X's region to C -n,SPC -next diff | h -hiliting | r -restore buf C's old diff - j -jump to diff | @ -auto-refinement | * -refine current region - gx -goto X's point| ## -ignore whitespace | ! -update diff regions - C-l -recenter | #f/#h -focus/hide regions | + -combine diff regions - v/V -scroll up/dn | X -read-only in buf X | wx -save buf X - -scroll lt/rt | m -wide display | wd -save diff output - ~ -swap variants | s -shrink window C | / -show ancestor buff - | $ -show clashes only | & -merge w/new default -" - "Help message during merging. -Normally, not a user option. See `ediff-help-message' for details.") - -;; The actual long help message. -(ediff-defvar-local ediff-long-help-message "" - "Normally, not a user option. See `ediff-help-message' for details.") - -(defconst ediff-brief-message-string - " ? - help " - "Contents of the brief help message.") -;; The actual brief help message -(ediff-defvar-local ediff-brief-help-message "" - "Normally, not a user option. See `ediff-help-message' for details.") - -(ediff-defvar-local ediff-brief-help-message-function nil - "The brief help message that the user can customize. -If the user sets this to a parameter-less function, Ediff will use it to -produce the brief help message. This function must return a string.") -(ediff-defvar-local ediff-long-help-message-function nil - "The long help message that the user can customize. -See `ediff-brief-help-message-function' for more.") - -(defvar ediff-use-long-help-message nil - "*If t, Ediff displays a long help message. Short help message otherwise.") - -;; The actual help message. -(ediff-defvar-local ediff-help-message "" - "The actual help message. -Normally, the user shouldn't touch this. However, if you want Ediff to -start up with different help messages for different jobs, you can change -the value of this variable and the variables `ediff-help-message-*' in -`ediff-startup-hook'.") - ;; Error messages (defconst ediff-KILLED-VITAL-BUFFER "You have killed a vital Ediff buffer---you must leave Ediff now!") @@ -477,6 +367,12 @@ the value of this variable and the variables `ediff-help-message-*' in (defconst ediff-BAD-DIFF-NUMBER ;; %S stands for this-command, %d - diff number, %d - max diff "%S: Bad diff region number, %d. Valid numbers are 1 to %d") +(defconst ediff-BAD-INFO (format " +*** The Info file for Ediff, a part of the standard distribution +*** of %sEmacs, does not seem to be properly installed. +*** +*** Please contact your system administrator. " + (if ediff-xemacs-p "X" ""))) ;; Selective browsing @@ -517,12 +413,6 @@ See the documentation string of `ediff-focus-on-regexp-matches' for details.") (ediff-defvar-local ediff-hide-regexp-connective 'and "") -(defvar ediff-ange-ftp-ftp-name (if ediff-xemacs-p - 'ange-ftp-ftp-path - 'ange-ftp-ftp-name) - "Function ange-ftp uses to find out if file is remote.") - - ;; Copying difference regions between buffers. (ediff-defvar-local ediff-killed-diffs-alist nil "A list of killed diffs. @@ -617,8 +507,8 @@ ediff-toggle-hilit. Use `setq-default' to set it.") (ediff-defvar-local ediff-buffer-values-orig-Ancestor nil "") ;; Buffer-local variables to be saved then restored during Ediff sessions ;; Buffer-local variables to be saved then restored during Ediff sessions -(defconst ediff-protected-variables '(buffer-read-only -;;; synchronize-minibuffers +(defconst ediff-protected-variables '( + ;;buffer-read-only mode-line-format)) ;; Vector of differences between the variants. Each difference is @@ -863,6 +753,15 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") (copy-face 'secondary-selection face)))) )) +(defun ediff-set-face-pixmap (face pixmap) + "Set face pixmap on a monochrome display." + (if (and (ediff-window-display-p) (not (ediff-color-display-p))) + (condition-case nil + (set-face-background-pixmap face pixmap) + (error + (message "Pixmap not found for %S: %s" (face-name face) pixmap) + (sit-for 1))))) + (defun ediff-hide-face (face) (if (and (ediff-has-face-support-p) ediff-emacs-p) (add-to-list 'facemenu-unlisted-faces face))) @@ -935,6 +834,13 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") 'ediff-current-diff-face-C 'ediff-current-diff-face-Ancestor)))) "Face for highlighting the selected difference in the ancestor buffer.") +(defvar ediff-fine-diff-pixmap "gray3" + "Pixmap to use for highlighting fine differences.") +(defvar ediff-odd-diff-pixmap "gray1" + "Pixmap to use for highlighting odd differences.") +(defvar ediff-even-diff-pixmap "Stipple" + "Pixmap to use for highlighting even differences.") + (defvar ediff-fine-diff-face-A (if (ediff-has-face-support-p) (progn @@ -946,7 +852,11 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") "Navy") (ediff-set-face 'background 'ediff-fine-diff-face-A "sky blue")) - (t (set-face-underline-p 'ediff-fine-diff-face-A t)))) + (t + (set-face-underline-p 'ediff-fine-diff-face-A t) + (ediff-set-face-pixmap 'ediff-fine-diff-face-A + ediff-fine-diff-pixmap) + ))) 'ediff-fine-diff-face-A)) "Face for highlighting the refinement of the selected diff in buffer A.") @@ -959,7 +869,11 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") (cond ((ediff-color-display-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)))) + (t + (set-face-underline-p 'ediff-fine-diff-face-B t) + (ediff-set-face-pixmap 'ediff-fine-diff-face-B + ediff-fine-diff-pixmap) + ))) 'ediff-fine-diff-face-B)) "Face for highlighting the refinement of the selected diff in buffer B.") @@ -973,7 +887,11 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") (ediff-set-face 'foreground 'ediff-fine-diff-face-C "black") (ediff-set-face 'background 'ediff-fine-diff-face-C "Turquoise")) - (t (set-face-underline-p 'ediff-fine-diff-face-C t)))) + (t + (set-face-underline-p 'ediff-fine-diff-face-C t) + (ediff-set-face-pixmap 'ediff-fine-diff-face-C + ediff-fine-diff-pixmap) + ))) 'ediff-fine-diff-face-C)) "Face for highlighting the refinement of the selected diff in buffer C.") @@ -983,8 +901,12 @@ appropriate symbol: `rcs', `pcl-cvs', or `generic-sc' if you so desire.") (make-face 'ediff-fine-diff-face-Ancestor) (ediff-hide-face 'ediff-fine-diff-face-Ancestor) (or (face-differs-from-default-p 'ediff-fine-diff-face-Ancestor) - (copy-face - 'ediff-fine-diff-face-C 'ediff-fine-diff-face-Ancestor)))) + (progn + (copy-face + 'ediff-fine-diff-face-C 'ediff-fine-diff-face-Ancestor) + (ediff-set-face-pixmap 'ediff-fine-diff-face-Ancestor + ediff-fine-diff-pixmap)) + ))) "Face highlighting refinements of the selected diff in ancestor buffer. Presently, this is not used, as difference regions are not refined in the ancestor buffer.") @@ -1001,7 +923,10 @@ ancestor buffer.") (ediff-set-face 'background 'ediff-even-diff-face-A "light grey")) (t - (copy-face 'italic 'ediff-even-diff-face-A)))) + (copy-face 'italic 'ediff-even-diff-face-A) + (ediff-set-face-pixmap 'ediff-even-diff-face-A + ediff-even-diff-pixmap) + ))) 'ediff-even-diff-face-A)) "Face used to highlight even-numbered differences in buffer A.") @@ -1017,7 +942,10 @@ ancestor buffer.") (ediff-set-face 'background 'ediff-even-diff-face-B "Gray")) (t - (copy-face 'italic 'ediff-even-diff-face-B)))) + (copy-face 'italic 'ediff-even-diff-face-B) + (ediff-set-face-pixmap 'ediff-even-diff-face-B + ediff-even-diff-pixmap) + ))) 'ediff-even-diff-face-B)) "Face used to highlight even-numbered differences in buffer B.") @@ -1027,7 +955,10 @@ ancestor buffer.") (make-face 'ediff-even-diff-face-C) (ediff-hide-face 'ediff-even-diff-face-C) (or (face-differs-from-default-p 'ediff-even-diff-face-C) - (copy-face 'ediff-even-diff-face-A 'ediff-even-diff-face-C)) + (progn + (copy-face 'ediff-even-diff-face-A 'ediff-even-diff-face-C) + (ediff-set-face-pixmap 'ediff-even-diff-face-C + ediff-even-diff-pixmap))) 'ediff-even-diff-face-C)) "Face used to highlight even-numbered differences in buffer C.") @@ -1037,7 +968,11 @@ ancestor buffer.") (make-face 'ediff-even-diff-face-Ancestor) (ediff-hide-face 'ediff-even-diff-face-Ancestor) (or (face-differs-from-default-p 'ediff-even-diff-face-Ancestor) - (copy-face 'ediff-even-diff-face-C 'ediff-even-diff-face-Ancestor)) + (progn + (copy-face + 'ediff-even-diff-face-C 'ediff-even-diff-face-Ancestor) + (ediff-set-face-pixmap 'ediff-even-diff-face-Ancestor + ediff-even-diff-pixmap))) 'ediff-even-diff-face-Ancestor)) "Face highlighting even-numbered differences in the ancestor buffer.") @@ -1053,7 +988,10 @@ ancestor buffer.") (ediff-set-face 'background 'ediff-odd-diff-face-A "Gray")) (t - (copy-face 'italic 'ediff-odd-diff-face-A)))) + (copy-face 'italic 'ediff-odd-diff-face-A) + (ediff-set-face-pixmap 'ediff-odd-diff-face-A + ediff-odd-diff-pixmap) + ))) 'ediff-odd-diff-face-A)) "Face used to highlight odd-numbered differences in buffer A.") @@ -1069,7 +1007,10 @@ ancestor buffer.") (ediff-set-face 'background 'ediff-odd-diff-face-B "light grey")) (t - (copy-face 'italic 'ediff-odd-diff-face-B)))) + (copy-face 'italic 'ediff-odd-diff-face-B) + (ediff-set-face-pixmap 'ediff-odd-diff-face-B + ediff-odd-diff-pixmap) + ))) 'ediff-odd-diff-face-B)) "Face used to highlight odd-numbered differences in buffer B.") @@ -1079,7 +1020,10 @@ ancestor buffer.") (make-face 'ediff-odd-diff-face-C) (ediff-hide-face 'ediff-odd-diff-face-C) (or (face-differs-from-default-p 'ediff-odd-diff-face-C) - (copy-face 'ediff-odd-diff-face-A 'ediff-odd-diff-face-C)) + (progn + (copy-face 'ediff-odd-diff-face-A 'ediff-odd-diff-face-C) + (ediff-set-face-pixmap 'ediff-odd-diff-face-C + ediff-odd-diff-pixmap))) 'ediff-odd-diff-face-C)) "Face used to highlight odd-numbered differences in buffer C.") @@ -1089,7 +1033,10 @@ ancestor buffer.") (make-face 'ediff-odd-diff-face-Ancestor) (ediff-hide-face 'ediff-odd-diff-face-Ancestor) (or (face-differs-from-default-p 'ediff-odd-diff-face-Ancestor) - (copy-face 'ediff-odd-diff-face-C 'ediff-odd-diff-face-Ancestor)) + (progn + (copy-face 'ediff-odd-diff-face-C 'ediff-odd-diff-face-Ancestor) + (ediff-set-face-pixmap 'ediff-odd-diff-face-Ancestor + ediff-odd-diff-pixmap))) 'ediff-odd-diff-face-Ancestor)) "Face used to highlight even-numbered differences in the ancestor buffer.") @@ -1147,6 +1094,15 @@ control is used, it could be `vc-toggle-read-only' or `rcs-toggle-read-only'.") ;; if nil, this silences some messages (defconst ediff-verbose-p t) + +(ediff-defvar-local ediff-autostore-merges 'group-jobs-only + "*Save the results of merge jobs automatically. +Nil means don't save automatically. t means always save. Anything but nil or t +means save automatically only if the merge job is part of a group of jobs, such +as `ediff-merge-directory' or `ediff-merge-directory-revisions'.") + +;; file where the result of the merge is to be saved. used internally +(ediff-defvar-local ediff-merge-store-file nil "") (defvar ediff-no-emacs-help-in-control-buffer nil "*Non-nil means C-h should not invoke Emacs help in control buffer. @@ -1192,8 +1148,10 @@ More precisely, a regexp to match any one such character.") ;;; In-line functions (defsubst ediff-file-remote-p (file-name) - (if (fboundp ediff-ange-ftp-ftp-name) - (funcall ediff-ange-ftp-ftp-name file-name))) + (require 'ange-ftp) + (car (if ediff-xemacs-p + (ange-ftp-ftp-path file-name) + (ange-ftp-ftp-name file-name)))) (defsubst ediff-frame-unsplittable-p (frame) @@ -1210,6 +1168,93 @@ More precisely, a regexp to match any one such character.") "Kill buffer BUF if it exists." (if (ediff-buffer-live-p buf) (kill-buffer (get-buffer buf)))) + + +;; activate faces on diff regions in buffer +(defun ediff-paint-background-regions-in-one-buffer (buf-type unhighlight) + (let ((diff-vector + (eval (intern (format "ediff-difference-vector-%S" buf-type)))) + overl diff-num) + (mapcar (function + (lambda (rec) + (setq overl (ediff-get-diff-overlay-from-diff-record rec) + diff-num (ediff-overlay-get overl 'ediff-diff-num)) + (ediff-set-overlay-face + overl + (if (not unhighlight) + (ediff-background-face buf-type diff-num)) + ))) + diff-vector))) + + +;; activate faces on diff regions in all buffers +(defun ediff-paint-background-regions (&optional unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'A unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'B unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'C unhighlight) + (ediff-paint-background-regions-in-one-buffer + 'Ancestor unhighlight)) + +(defun ediff-highlight-diff-in-one-buffer (n buf-type) + (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) + (let* ((buff (ediff-get-buffer buf-type)) + (last (ediff-eval-in-buffer buff (point-max))) + (begin (ediff-get-diff-posn buf-type 'beg n)) + (end (ediff-get-diff-posn buf-type 'end n)) + (xtra (if (equal begin end) 1 0)) + (end-hilit (min last (+ end xtra))) + (current-diff-overlay + (symbol-value + (intern (format "ediff-current-diff-overlay-%S" buf-type))))) + + (if ediff-xemacs-p + (ediff-move-overlay current-diff-overlay begin end-hilit) + (ediff-move-overlay current-diff-overlay begin end-hilit buff)) + (ediff-overlay-put current-diff-overlay 'priority + (ediff-highest-priority begin end-hilit buff)) + (ediff-overlay-put current-diff-overlay 'ediff-diff-num n) + + ;; unhighlight the background overlay for diff n so it won't + ;; interfere with the current diff overlay + (ediff-set-overlay-face (ediff-get-diff-overlay n buf-type) nil) + ))) + + +(defun ediff-unhighlight-diff-in-one-buffer (buf-type) + (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) + (let ((current-diff-overlay + (symbol-value + (intern (format "ediff-current-diff-overlay-%S" buf-type)))) + (overlay + (ediff-get-diff-overlay ediff-current-difference buf-type)) + ) + + (ediff-move-overlay current-diff-overlay 1 1) + + ;; rehighlight the overlay in the background of the + ;; current difference region + (ediff-set-overlay-face + overlay + (if (and (ediff-has-face-support-p) + ediff-use-faces ediff-highlight-all-diffs) + (ediff-background-face buf-type ediff-current-difference))) + ))) + +(defun ediff-unhighlight-diffs-totally-in-one-buffer (buf-type) + (ediff-unselect-and-select-difference -1) + (if (and (ediff-has-face-support-p) ediff-use-faces) + (let* ((inhibit-quit t) + (current-diff-overlay-var + (intern (format "ediff-current-diff-overlay-%S" buf-type))) + (current-diff-overlay (symbol-value current-diff-overlay-var))) + (ediff-paint-background-regions 'unhighlight) + (if (ediff-overlayp current-diff-overlay) + (ediff-delete-overlay current-diff-overlay)) + (set current-diff-overlay-var nil) + ))) (defsubst ediff-highlight-diff (n) @@ -1367,6 +1412,7 @@ More precisely, a regexp to match any one such character.") (glyph-height ediff-H-glyph (selected-window frame)) (frame-char-height frame))) +;; Some overlay functions (defsubst ediff-empty-overlay-p (overl) (= (ediff-overlay-start overl) (ediff-overlay-end overl))) @@ -1384,6 +1430,32 @@ More precisely, a regexp to match any one such character.") (if ediff-emacs-p (overlay-get overl property) (and (extent-live-p overl) (extent-property overl property)))) + + +;; These two functions are here because XEmacs refuses to +;; handle overlays whose buffers were deleted. +(defun ediff-move-overlay (overlay beg end &optional buffer) + "Calls `move-overlay' in Emacs and `set-extent-endpoints' in Lemacs. +Checks if overlay's buffer exists before actually doing the move." + (let ((buf (and overlay (ediff-overlay-buffer overlay)))) + (if (ediff-buffer-live-p buf) + (if ediff-xemacs-p + (set-extent-endpoints overlay beg end) + (move-overlay overlay beg end buffer)) + ;; buffer's dead + (if overlay + (ediff-delete-overlay overlay))))) + +(defun ediff-overlay-put (overlay prop value) + "Calls `overlay-put' or `set-extent-property' depending on Emacs version. +Checks if overlay's buffer exists." + (if (ediff-buffer-live-p (ediff-overlay-buffer overlay)) + (if ediff-xemacs-p + (set-extent-property overlay prop value) + (overlay-put overlay prop value)) + (ediff-delete-overlay overlay))) + +;; Some diff region tests ;; t if diff region is empty. ;; In case of buffer C, t also if it is not a 3way @@ -1516,8 +1588,18 @@ More precisely, a regexp to match any one such character.") (ediff-file-attributes filename 5)) +(defun ediff-convert-standard-filename (fname) + (if ediff-emacs-p + (convert-standard-filename fname) + ;; hopefully, XEmacs adds this functionality + fname)) +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) +;;; End: (provide 'ediff-init) diff --git a/lisp/ediff-merg.el b/lisp/ediff-merg.el index 80275c46f3..a07dc8d8c1 100644 --- a/lisp/ediff-merg.el +++ b/lisp/ediff-merg.el @@ -264,6 +264,12 @@ Combining is done according to the specifications in variable ))) +;;; Local Variables: +;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) +;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) +;;; End: + (provide 'ediff-merg) ;; ediff-merg.el ends here diff --git a/lisp/ediff-mult.el b/lisp/ediff-mult.el index 7bfdd81e47..2a88f9dc03 100644 --- a/lisp/ediff-mult.el +++ b/lisp/ediff-mult.el @@ -155,6 +155,8 @@ directories.") (defvar ediff-session-group-setup-hook nil "*Hooks run just after a meta-buffer controlling a session group, such as ediff-directories, is run.") +(defvar ediff-quit-session-group-hook nil + "*Hooks run just before exiting a session group.") (defvar ediff-show-registry-hook nil "*Hooks run just after the registry buffer is shown.") (defvar ediff-show-session-group-hook nil @@ -168,6 +170,7 @@ ediff-directories, is run.") ;; group buffer/regexp (defun ediff-get-group-buffer (meta-list) (nth 0 (car meta-list))) + (defun ediff-get-group-regexp (meta-list) (nth 1 (car meta-list))) ;; group objects @@ -177,6 +180,9 @@ ediff-directories, is run.") (nth 3 (car meta-list))) (defun ediff-get-group-objC (meta-list) (nth 4 (car meta-list))) +(defun ediff-get-group-merge-autostore-dir (meta-list) + (nth 5 (car meta-list))) + ;; session buffer (defun ediff-get-session-buffer (elt) (nth 0 elt)) @@ -313,11 +319,16 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (backward-char 1))) )) +(defsubst ediff-add-slash-if-directory (dir file) + (if (file-directory-p (concat dir file)) + (file-name-as-directory file) + file)) -;; DIR1, DIR2, DIR3 are directories. -;; REGEXP is a regexp used to filter -;; files in the directories. +;; DIR1, DIR2, DIR3 are directories. DIR3 can be nil. +;; OUTPUT-DIR is a directory for auto-storing the results of merge jobs. +;; Can be nil. +;; REGEXP is a regexp used to filter out files in the directories. ;; If a file is a directory in dir1 but not dir2 (or vice versa), it is not ;; included in the intersection. However, a regular file that is a dir in dir3 ;; is included, since dir3 files are supposed to be ancestors for merging. @@ -325,44 +336,53 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." ;; ((dir1 dir2 dir3) (f1 f2 f3) (f1 f2 f3) ...) ;; dir3, f3 can be nil if intersecting only 2 directories. ;; If COMPARISON-FUNC is given, use it. Otherwise, use string= -;; DIFF-VAR is contains the name of the variable in which to return the -;; difference list. The diff list is of the form: +;; DIFF-VAR contains the name of the variable in which to return the +;; difference list (which represents the differences among the contents of +;; directories). The diff list is of the form: ;; ((dir1 dir2 dir3) (file . num) (file . num)...) ;; where num encodes the set of dirs where the file is found: ;; 2 - only dir1; 3 - only dir2; 5 - only dir3; 6 - dir1&2; 10 - dir1&3; etc. (defun ediff-intersect-directories (jobname diff-var regexp dir1 dir2 - &optional dir3 comparison-func) + &optional + dir3 merge-autostore-dir comparison-func) (setq comparison-func (or comparison-func 'string=)) (let (lis1 lis2 lis3 common auxdir1 auxdir2 auxdir3 difflist) (setq auxdir1 (file-name-as-directory dir1) lis1 (directory-files auxdir1 nil regexp) + lis1 (delete "." lis1) + lis1 (delete ".." lis1) + lis1 (mapcar + (function + (lambda (elt) + (ediff-add-slash-if-directory auxdir1 elt))) + lis1) auxdir2 (file-name-as-directory dir2) - lis2 (directory-files auxdir2 nil regexp)) + lis2 (mapcar + (function + (lambda (elt) + (ediff-add-slash-if-directory auxdir2 elt))) + (directory-files auxdir2 nil regexp))) (if (stringp dir3) (setq auxdir3 (file-name-as-directory dir3) - lis3 (directory-files auxdir3 nil regexp))) - - (setq lis1 (delete "." lis1) - lis1 (delete ".." lis1)) - + lis3 (mapcar + (function + (lambda (elt) + (ediff-add-slash-if-directory auxdir3 elt))) + (directory-files auxdir3 nil regexp)))) + + (if (stringp merge-autostore-dir) + (setq merge-autostore-dir + (file-name-as-directory merge-autostore-dir))) (setq common (ediff-intersection lis1 lis2 comparison-func)) - ;; get rid of files that are directories in dir1 but not dir2 - (mapcar (function (lambda (elt) - (if (Xor (file-directory-p (concat auxdir1 elt)) - (file-directory-p (concat auxdir2 elt))) - (setq common (delq elt common))))) - common) - ;; intersect with the third dir - (if lis3 (setq common (ediff-intersection common lis3 comparison-func))) - (if (ediff-comparison-metajob3 jobname) - (mapcar (function (lambda (elt) - (if (Xor (file-directory-p (concat auxdir1 elt)) - (file-directory-p (concat auxdir3 elt))) - (setq common (delq elt common))))) - common)) + + ;; In merge with ancestor jobs, we don't intersect with lis3. + ;; If there is no ancestor, we'll offer to merge without the ancestor. + ;; So, we intersect with lis3 only when we are doing 3-way file comparison + (if (and lis3 (ediff-comparison-metajob3 jobname)) + (setq common (ediff-intersection common lis3 comparison-func))) ;; copying is needed because sort sorts via side effects (setq common (sort (ediff-copy-list common) 'string-lessp)) @@ -393,25 +413,47 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." difflist) (setq difflist (cons (list regexp auxdir1 auxdir2 auxdir3) difflist)) + ;; return the difference list back to the calling function (set diff-var difflist) ;; return result - (cons (list regexp auxdir1 auxdir2 auxdir3) - (mapcar (function (lambda (elt) - (list (concat auxdir1 elt) - (concat auxdir2 elt) - (if lis3 - (concat auxdir3 elt))))) - common)) + (cons (list regexp auxdir1 auxdir2 auxdir3 merge-autostore-dir) + (mapcar + (function + (lambda (elt) + (list (concat auxdir1 elt) + (concat auxdir2 elt) + (if lis3 + (progn + ;; The following is done because: + ;; In merging with ancestor, we don't intersect + ;; with lis3. So, it is possible that elt is a + ;; file in auxdir1/2 but a directory in auxdir3 + ;; Or elt may not exist in auxdir3 at all. + ;; In the first case, we add a slash at the end. + ;; In the second case, we insert nil. + (setq elt (ediff-add-slash-if-directory auxdir3 elt)) + (if (file-exists-p (concat auxdir3 elt)) + (concat auxdir3 elt))))))) + common)) )) ;; find directory files that are under revision. -;; display subdirectories, too, since we may visit them recursively. -(defun ediff-get-directory-files-under-revision (jobname regexp dir1) +;; Include subdirectories, since we may visit them recursively. +;; DIR1 is the directory to inspect. +;; OUTPUT-DIR is the directory where to auto-store the results of merges. Can +;; be nil. +(defun ediff-get-directory-files-under-revision (jobname + regexp dir1 + &optional merge-autostore-dir) (let (lis1 elt common auxdir1) (setq auxdir1 (file-name-as-directory dir1) lis1 (directory-files auxdir1 nil regexp)) + (if (stringp merge-autostore-dir) + (setq merge-autostore-dir + (file-name-as-directory merge-autostore-dir))) + (while lis1 (setq elt (car lis1) lis1 (cdr lis1)) @@ -426,13 +468,14 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." ) ; while (setq common (delete "." common) - common (delete ".." common)) + common (delete ".." common) + common (delete "RCS" common)) ;; copying is needed because sort sorts via side effects (setq common (sort (ediff-copy-list common) 'string-lessp)) ;; return result - (cons (list regexp auxdir1 nil nil) + (cons (list regexp auxdir1 nil nil merge-autostore-dir) (mapcar (function (lambda (elt) (list (concat auxdir1 elt) nil nil))) @@ -499,28 +542,32 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." ;; meta-buffs. (define-key ediff-meta-buffer-map "M" 'ediff-show-meta-buff-from-registry)) - ;; initialize the meta list -- don't do this for registry we prepend - ;; '(nil nil) to all elts of meta-list, except the first. The - ;; first nil will later be replaced by the session buffer. The second - ;; is reserved for session status. + ;; Initialize the meta list -- don't do this for registry. + ;; + ;; We prepend '(nil nil) to all elts of meta-list, except the first. + ;; The first nil will later be replaced by the session buffer. The + ;; second is reserved for session status. + ;; ;; (car ediff-meta-list) gets cons'ed with the session group buffer. - ;; Also, session objA/B/C are turned into lists (obj eq-indicator) + ;; Also, session objects A/B/C are turned into lists of the form + ;; (obj eq-indicator). Eq-indicator is either nil or =. Initialized to + ;; nil. If later it is discovered that this file is = to some other + ;; file in the same session, eq-indicator is changed to `='. ;; For now, the eq-indicator is used only for 2 and 3-file jobs. (setq ediff-meta-list (cons (cons meta-buffer (car meta-list)) - (mapcar (function - (lambda (elt) - (cons nil - (cons nil - ;; convert each obj to (obj nil), - ;; where nil may later be replaced - ;; by =, if this file equals some - ;; other file in the same session - (mapcar (function - (lambda (obj) - (list obj nil))) - elt))))) - (cdr meta-list))))) + (mapcar + (function + (lambda (elt) + (cons nil + (cons nil + ;; convert each obj to (obj nil), + ;; where nil is the initial value + ;; for eq-indicator -- see above + (mapcar + (function (lambda (obj) (list obj nil))) + elt))))) + (cdr meta-list))))) (or (eq meta-buffer ediff-registry-buffer) (setq ediff-session-registry @@ -534,8 +581,9 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (set-buffer-modified-p nil) (run-hooks 'startup-hooks) - ;; arrange for showing directory contents differences - ;; must be after run startup-hooks, since ediff-dir-difference-list is + + ;; Arrange to show directory contents differences + ;; Must be after run startup-hooks, since ediff-dir-difference-list is ;; set inside these hooks (if (eq action-func 'ediff-filegroup-action) (progn @@ -574,6 +622,7 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (empty t) (sessionNum 0) regexp elt session-buf f1 f2 f3 pt + merge-autostore-dir point tmp-list buffer-read-only) (ediff-eval-in-buffer meta-buf (setq point (point)) @@ -581,7 +630,8 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (insert (format ediff-meta-buffer-message (ediff-abbrev-jobname ediff-metajob-name))) - (setq regexp (ediff-get-group-regexp meta-list)) + (setq regexp (ediff-get-group-regexp meta-list) + merge-autostore-dir (ediff-get-group-merge-autostore-dir meta-list)) (cond ((ediff-collect-diffs-metajob) (insert @@ -598,7 +648,11 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (if (and (stringp regexp) (> (length regexp) 0)) (insert (format "Filter-through regular expression: %s\n" regexp))) - + (if (and ediff-autostore-merges (ediff-merge-metajob) + (stringp merge-autostore-dir)) + (insert (format + "\nMerges are automatically stored in directory: %s\n" + merge-autostore-dir))) (insert "\n Size Last modified Name ----------------------------------------------------------------------- @@ -621,7 +675,6 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." ;; now organize file names like this: ;; use-mark sizeA dateA sizeB dateB filename ;; make sure directories are displayed with a trailing slash. - ;; If one is a directory and another isn't, indicate this with a `?' (while meta-list (setq elt (car meta-list) meta-list (cdr meta-list) @@ -652,50 +705,63 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." ;; Check if this is a problematic session. ;; Return nil if not. Otherwise, return symbol representing the problem ;; At present, problematic sessions occur only in -with-ancestor comparisons -;; when the ancestor is a directory rather than a file. +;; when the ancestor is a directory rather than a file, or when there is no +;; suitable ancestor file in the ancestor directory (defun ediff-problematic-session-p (session) (let ((f1 (ediff-get-session-objA-name session)) (f2 (ediff-get-session-objB-name session)) (f3 (ediff-get-session-objC-name session))) (cond ((and (stringp f1) (not (file-directory-p f1)) (stringp f2) (not (file-directory-p f2)) - (stringp f3) (file-directory-p f3) + ;; either invalid file name or a directory + (or (not (stringp f3)) (file-directory-p f3)) (ediff-ancestor-metajob)) ;; more may be added later 'ancestor-is-dir) (t nil)))) (defun ediff-meta-insert-file-info (fileinfo) - (let ((file-size -1) - (fname (car fileinfo)) + (let ((fname (car fileinfo)) (feq (ediff-get-file-eqstatus fileinfo)) - (file-modtime "*file doesn't exist*")) - - (if (and (stringp fname) (file-exists-p fname)) - (setq file-size (ediff-file-size fname) - file-modtime (ediff-file-modtime fname))) + file-modtime file-size) + + (cond ((not (stringp fname)) (setq file-size -2)) ; file doesn't exits + ((not (ediff-file-remote-p fname)) + (if (file-exists-p fname) + ;; set real size and modtime + (setq file-size (ediff-file-size fname) + file-modtime (ediff-file-modtime fname)) + (setq file-size -2))) ; file doesn't exist + ( t (setq file-size -1))) ; remote file (if (stringp fname) (insert (format "%s %s %-20s %s\n" (if feq "=" " ") ; equality indicator - (format "%10s" (if (< file-size 0) - "remote" - file-size)) - (if (< file-size 0) - "file" - (ediff-format-date (decode-time file-modtime))) - ;; dir names in meta lists have no trailing `/' so insert it - (cond ((file-directory-p fname) - (file-name-as-directory (ediff-abbreviate-file-name fname))) - (t (ediff-abbreviate-file-name fname))))) - ))) + (format "%10s" (cond ((= file-size -1) "--") + ((< file-size -1) "--") + (t file-size))) + (cond ((= file-size -1) "*remote file*") + ((< file-size -1) "*file doesn't exist*") + (t (ediff-format-date (decode-time file-modtime)))) + + ;; dir names in meta lists have training slashes, so we just + ;; abbreviate the file name, if file exists + (if (and (not (stringp fname)) (< file-size -1)) + "-------" ; file doesn't exist + (ediff-abbreviate-file-name fname))))))) (defconst ediff-months '((1 . "Jan") (2 . "Feb") (3 . "Mar") (4 . "Apr") (5 . "May") (6 . "Jun") (7 . "Jul") (8 . "Aug") (9 . "Sep") (10 . "Oct") (11 . "Nov") (12 . "Dec")) "Months' associative array.") +;; returns 2char string +(defsubst ediff-fill-leading-zero (num) + (if (< num 10) + (format "0%d" num) + (number-to-string num))) + ;; TIME is like the output of decode-time (defun ediff-format-date (time) (format "%s %2d %4d %s:%s:%s" @@ -707,12 +773,6 @@ Moves in circular fashion. With numeric prefix arg, skip this many items." (ediff-fill-leading-zero (nth 0 time)) ; sec )) -;; returns 2char string -(defsubst ediff-fill-leading-zero (num) - (if (< num 10) - (format "0%d" num) - (number-to-string num))) - (defun ediff-draw-dir-diffs (diff-list) (if (null diff-list) (error "Lost difference info on these directories")) (let* ((buf-name (ediff-unique-buffer-name @@ -1130,6 +1190,7 @@ all marked sessions must be active." (meta-buf (ediff-event-buffer last-command-event)) ;; ediff-get-meta-info gives error if meta-buf or pos are invalid (info (ediff-get-meta-info meta-buf pos)) + merge-autostore-dir session-buf file1 file2 file3 regexp) (setq session-buf (ediff-get-session-buffer info) @@ -1149,6 +1210,8 @@ all marked sessions must be active." (error "Aborted")))) (ediff-eval-in-buffer meta-buf + (setq merge-autostore-dir + (ediff-get-group-merge-autostore-dir ediff-meta-list)) (goto-char pos) ; if the user clicked on session--move point there ;; First handle sessions involving directories (which are themselves ;; session groups) @@ -1203,13 +1266,19 @@ all marked sessions must be active." ((ediff-problematic-session-p info) (beep) (if (y-or-n-p - "This session's ancestor is a directory, merge without the ancestor? ") + "This session has no ancestor. Merge without the ancestor? ") (ediff-merge-files file1 file2 ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - ;; see below for the explanation of what this does + (setq ediff-merge-store-file + (, (concat + merge-autostore-dir + (file-name-nondirectory file1)))) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below (setcar (quote (, info)) ediff-control-buffer))))) (error "Aborted"))) @@ -1219,7 +1288,13 @@ all marked sessions must be active." ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - ;; see below for explanation of what this does + (setq ediff-merge-store-file + (, (concat + merge-autostore-dir + (file-name-nondirectory file1)))) + ;; make ediff-startup pass + ;; ediff-control-buffer back to the meta + ;; level; see below (setcar (quote (, info)) ediff-control-buffer)))))) ((not (ediff-metajob3)) ; need 2 file args @@ -1228,12 +1303,13 @@ all marked sessions must be active." ;; provide startup hooks (` (list (lambda () (setq ediff-meta-buffer (, (current-buffer))) - ;; this makes ediff-startup pass the value of + (setq ediff-merge-store-file + (, (concat + merge-autostore-dir + (file-name-nondirectory file1)))) + ;; make ediff-startup pass ;; ediff-control-buffer back to the meta - ;; level, to the record in the meta list - ;; containing the information about the - ;; session associated with that - ;; ediff-control-buffer + ;; level; see below (setcar (quote (, info)) ediff-control-buffer)))))) ((ediff-metajob3) ; need 3 file args @@ -1241,7 +1317,17 @@ all marked sessions must be active." file1 file2 file3 ;; arrange startup hooks (` (list (lambda () + (setq ediff-merge-store-file + (, (concat + merge-autostore-dir + (file-name-nondirectory file1)))) (setq ediff-meta-buffer (, (current-buffer))) + ;; this arranges that ediff-startup will pass + ;; the value of ediff-control-buffer back to + ;; the meta level, to the record in the meta + ;; list containing the information about the + ;; session associated with that + ;; ediff-control-buffer (setcar (quote (, info)) ediff-control-buffer)))))) ) ; cond @@ -1404,8 +1490,8 @@ all marked sessions must be active." 'ediff-registry)) )) -;; if meta-buf exists, it is redrawn along with parent. Otherwise, nothing -;; happens +;; If meta-buf exists, it is redrawn along with parent. +;; Otherwise, nothing happens. (defun ediff-cleanup-meta-buffer (meta-buffer) (if (ediff-buffer-live-p meta-buffer) (ediff-eval-in-buffer meta-buffer @@ -1430,7 +1516,7 @@ all marked sessions must be active." cont)))) (defun ediff-quit-meta-buffer () - "If no unprocessed sessions in the group, delete the meta buffer. + "If the group has no active session, delete the meta buffer. If no session is in progress, ask to confirm before deleting meta buffer. Otherwise, bury the meta buffer. If this is a session registry buffer then just bury it." @@ -1445,6 +1531,7 @@ If this is a session registry buffer then just bury it." (ediff-cleanup-meta-buffer buf) (cond ((and (ediff-safe-to-quit buf) (y-or-n-p "Quit this session group? ")) + (run-hooks 'ediff-quit-session-group-hook) (message "") (ediff-dispose-of-meta-buffer buf)) ((ediff-safe-to-quit buf) @@ -1617,6 +1704,7 @@ This is used only for sessions that involve 2 or 3 files at the same time." ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-mult) diff --git a/lisp/ediff-ptch.el b/lisp/ediff-ptch.el index bd74071388..960eb6fda9 100644 --- a/lisp/ediff-ptch.el +++ b/lisp/ediff-ptch.el @@ -32,7 +32,25 @@ (defvar ediff-backup-extension (if (memq system-type '(vax-vms axp-vms emx ms-dos windows-nt windows-95)) "_orig" ".orig") - "Default backup extension for the patch program.") + "Backup extension used by the patch program. +See also `ediff-backup-specs'.") + +(defvar ediff-backup-specs (format "-b %s" ediff-backup-extension) + "*Backup directives to pass to the patch program. +Ediff requires that the old version of the file \(before applying the patch\) +is saved in a file named `the-patch-file.extension'. Usually `extension' is +`.orig', but this can be changed by the user and may depend on the system. +Therefore, Ediff needs to know the backup extension used by the patch program. + +Some versions of the patch program let you specify `-b backup-extension'. +Other versions only permit `-b', which assumes some canned extension + \(usually `.orig'\). + +Note that both `ediff-backup-extension' and `ediff-backup-specs' +must be properly set. If your patch program takes the option `-b', +but not `-b extension', the variable `ediff-backup-extension' must +still be set so Ediff will know which extension to use.") + (defvar ediff-patch-default-directory nil "*Default directory to look for patches.") @@ -46,9 +64,16 @@ "*Regexp matching filename 2-liners at the start of each context diff.") (defvar ediff-patch-program "patch" - "*Name of the program that applies patches.") -(defvar ediff-patch-options "" - "*Options to pass to ediff-patch-program.") + "*Name of the program that applies patches. +It is recommended to use GNU-compatible versions.") +(defvar ediff-patch-options "-f" + "*Options to pass to ediff-patch-program. + +Note: the `-b' option should be specified in `ediff-backup-specs'. + +It is recommended to pass the `-f' option to the patch program, so it won't ask +questions. However, some implementations don't accept this option, in which +case the default value for this variable should be changed.") ;; The buffer of the patch file. Local to control buffer. (ediff-defvar-local ediff-patchbufer nil "") @@ -113,9 +138,9 @@ (setq mark2 (move-marker (make-marker) (match-beginning 0)) mark2-end (match-end 0) beg1 (or (match-beginning 2) (match-beginning 4)) - end1 (or (match-end 2) (match-end 4)) - beg2 (or (match-beginning 3) (match-beginning 5)) - end2 (or (match-end 3) (match-end 5))) + end1 (or (match-end 2) (match-end 4)) + beg2 (or (match-beginning 3) (match-beginning 5)) + end2 (or (match-end 3) (match-end 5))) ;; possible-file-names is holding the new file names until we ;; insert the old file name in the patch map ;; It is a pair (filename from 1st header line . fn from 2nd line) @@ -199,6 +224,7 @@ (princ (format " The patch file contains a context diff for + %s %s @@ -320,7 +346,8 @@ Else, read patch file into a new buffer." (current-buffer) 'must-match))) (setq patch-buf (find-file-noselect - (read-file-name "Which file contains the patch? " dir)))) + (read-file-name "Which file contains the patch? " + dir nil 'must-match)))) (ediff-eval-in-buffer patch-buf (goto-char (point-min)) @@ -406,15 +433,7 @@ Else, read patch file into a new buffer." &optional startup-hooks) (setq source-filename (expand-file-name source-filename)) - (let* ((backup-extension - ;; if the user specified a -b option, extract the backup - ;; extension from there; else use ediff-backup-extension - (substring ediff-patch-options - (if (string-match "-b[ \t]+" ediff-patch-options) - (match-end 0) 0) - (if (string-match "-b[ \t]+[^ \t]+" ediff-patch-options) - (match-end 0) 0))) - (shell-file-name ediff-shell) + (let* ((shell-file-name ediff-shell) (patch-diagnostics (get-buffer-create "*ediff patch diagnostics*")) ;; ediff-find-file may use a temp file to do the patch ;; so, we save source-filename and true-source-filename as a var @@ -422,12 +441,9 @@ Else, read patch file into a new buffer." ;; file for the purpose of patching. (true-source-filename source-filename) (target-filename source-filename) - target-buf buf-to-patch file-name-magic-p ctl-buf backup-style) + target-buf buf-to-patch file-name-magic-p + patch-return-code ctl-buf backup-style aux-wind) - ;; if the user didn't specify a backup extension, use - ;; ediff-backup-extension - (if (string= backup-extension "") - (setq backup-extension ediff-backup-extension)) (if (string-match "-V" ediff-patch-options) (error "Ediff doesn't take the -V option in `ediff-patch-options'--sorry")) @@ -457,14 +473,21 @@ Else, read patch file into a new buffer." ;; fix environment for gnu patch, so it won't make numbered extensions (setq backup-style (getenv "VERSION_CONTROL")) (setenv "VERSION_CONTROL" nil) - ;; always pass patch the -f option, so it won't ask any questions - (shell-command-on-region - (point-min) (point-max) - (format "%s -f %s -b %s %s" - ediff-patch-program ediff-patch-options - backup-extension - (expand-file-name true-source-filename)) - t) + (setq patch-return-code + (call-process-region + (point-min) (point-max) + shell-file-name + t ; delete region (which contains the patch + t ; insert output (patch diagnostics) in current buffer + nil ; don't redisplay + shell-command-switch ; usually -c + (format "%s %s %s %s" + ediff-patch-program + ediff-patch-options + ediff-backup-specs + (expand-file-name true-source-filename)) + )) + ;; restore environment for gnu patch (setenv "VERSION_CONTROL" backup-style)) @@ -474,9 +497,46 @@ Else, read patch file into a new buffer." (switch-to-buffer patch-diagnostics) (sit-for 0) ; synchronize - let the user see diagnostics - (or (file-exists-p (concat true-source-filename backup-extension)) - (error "Patch appears to have failed")) - + (or (and (eq patch-return-code 0) ; patch reported success + (file-exists-p + (concat true-source-filename ediff-backup-extension))) + (progn + (with-output-to-temp-buffer ediff-msg-buffer + (princ (format " +Patch has failed OR the backup version of the patched file was not created by +the patch program. + +A possible reason is that the values of the variables + +ediff-patch-options = %S +ediff-backup-extension = %S +ediff-backup-specs = %S + +are not appropriate for the program specified in the variable + +ediff-patch-program = %S + +See Ediff on-line manual for more details on these variables. +\(Or use a GNU-compatible patch program and stay out of trouble.\) + +Type any key to continue... " + ediff-patch-options + ediff-backup-extension + ediff-backup-specs + ediff-patch-program))) + (beep 1) + (if (setq aux-wind (get-buffer-window ediff-msg-buffer)) + (progn + (select-window aux-wind) + (goto-char (point-max)))) + (read-char-exclusive) + (if aux-wind (bury-buffer)) ; ediff-msg-buffer + (if (setq aux-wind (get-buffer-window patch-diagnostics)) + (progn + (select-window aux-wind) + (bury-buffer))) + (error "Patch appears to have failed"))) + ;; If black magic is involved, apply patch to a temp copy of the ;; file. Otherwise, apply patch to the orig copy. If patch is applied ;; to temp copy, we name the result old-name_patched for local files @@ -487,7 +547,8 @@ Else, read patch file into a new buffer." ;; the original. (if (not file-name-magic-p) (ediff-eval-in-buffer buf-to-patch - (set-visited-file-name (concat source-filename backup-extension)) + (set-visited-file-name + (concat source-filename ediff-backup-extension)) (set-buffer-modified-p nil)) ;; Black magic in effect. @@ -504,7 +565,7 @@ Else, read patch file into a new buffer." (rename-file true-source-filename target-filename t) ;; arrange that the temp copy of orig will be deleted - (rename-file (concat true-source-filename backup-extension) + (rename-file (concat true-source-filename ediff-backup-extension) true-source-filename t)) ;; make orig buffer read-only @@ -557,6 +618,7 @@ Else, read patch file into a new buffer." ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-ptch) diff --git a/lisp/ediff-util.el b/lisp/ediff-util.el index 76eaaddae1..f248135b5b 100644 --- a/lisp/ediff-util.el +++ b/lisp/ediff-util.el @@ -24,11 +24,17 @@ ;;; Code: (require 'ediff-init) +(require 'ediff-help) (require 'ediff-mult) ;; Pacify compiler and avoid the need in checking for boundp (defvar ediff-patch-diagnostics nil) (defvar ediff-patchbufer nil) +(and noninteractive + (eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (load-file "ediff-init.el") + (load-file "ediff-help.el")))) ;; end pacifier @@ -100,6 +106,10 @@ to invocation.") (setq ediff-mode-map (make-sparse-keymap)) (suppress-keymap ediff-mode-map) + (define-key ediff-mode-map + (if ediff-emacs-p [mouse-2] [button2]) 'ediff-help-for-quick-help) + (define-key ediff-mode-map "\C-m" 'ediff-help-for-quick-help) + (define-key ediff-mode-map "p" 'ediff-previous-difference) (define-key ediff-mode-map "\C-?" 'ediff-previous-difference) (define-key ediff-mode-map [backspace] 'ediff-previous-difference) @@ -183,6 +193,7 @@ to invocation.") (define-key ediff-mode-map "wa" 'ediff-save-buffer) (define-key ediff-mode-map "wb" 'ediff-save-buffer) (define-key ediff-mode-map "wd" 'ediff-save-buffer) + (define-key ediff-mode-map "=" 'ediff-inferior-compare-regions) (if (fboundp 'ediff-show-patch-diagnostics) (define-key ediff-mode-map "P" 'ediff-show-patch-diagnostics)) (if ediff-3way-job @@ -210,10 +221,13 @@ to invocation.") ;; It now returns control buffer so other functions can do post-processing (defun ediff-setup (buffer-A file-A buffer-B file-B buffer-C file-C startup-hooks setup-parameters) - (setq file-A (expand-file-name file-A)) - (setq file-B (expand-file-name file-B)) + ;; ediff-convert-standard-filename puts file names in the form appropriate + ;; for the OS at hand. + (setq file-A (ediff-convert-standard-filename (expand-file-name file-A))) + (setq file-B (ediff-convert-standard-filename (expand-file-name file-B))) (if (stringp file-C) - (setq file-C (expand-file-name file-C))) + (setq file-C + (ediff-convert-standard-filename (expand-file-name file-C)))) (let* ((control-buffer-name (ediff-unique-buffer-name "*Ediff Control Panel" "*")) (control-buffer (ediff-eval-in-buffer buffer-A @@ -461,6 +475,8 @@ to invocation.") (shrink-window-if-larger-than-buffer) (or (ediff-multiframe-setup-p) (ediff-indent-help-message)) + (ediff-set-help-overlays) + (set-buffer-modified-p nil) (ediff-refresh-mode-lines) (setq ediff-control-window (selected-window)) @@ -476,72 +492,7 @@ to invocation.") (goto-char (point-min)) (skip-chars-forward ediff-whitespace))) -;; assuming we are in control window, calculate length of the first line in -;; help message -(defun ediff-help-message-line-length () - (save-excursion - (goto-char (point-min)) - (if ediff-use-long-help-message - (next-line 1)) - (end-of-line) - (current-column))) - -(defun ediff-indent-help-message () - (let* ((shift (/ (max 0 (- (window-width (selected-window)) - (ediff-help-message-line-length))) - 2)) - (str (make-string shift ?\ ))) - (save-excursion - (goto-char (point-min)) - (while (< (point) (point-max)) - (insert str) - (beginning-of-line) - (forward-line 1))))) - - -(defun ediff-set-help-message () - (setq ediff-long-help-message - (cond ((and ediff-long-help-message-function - (or (symbolp ediff-long-help-message-function) - (consp ediff-long-help-message-function))) - (funcall ediff-long-help-message-function)) - (ediff-word-mode - (concat ediff-long-help-message-head - ediff-long-help-message-word-mode - ediff-long-help-message-tail)) - (ediff-narrow-job - (concat ediff-long-help-message-head - ediff-long-help-message-narrow2 - ediff-long-help-message-tail)) - (ediff-merge-job - (concat ediff-long-help-message-head - ediff-long-help-message-merge - ediff-long-help-message-tail)) - (ediff-diff3-job - (concat ediff-long-help-message-head - ediff-long-help-message-compare3 - ediff-long-help-message-tail)) - (t - (concat ediff-long-help-message-head - ediff-long-help-message-compare2 - ediff-long-help-message-tail)))) - (setq ediff-brief-help-message - (cond ((and ediff-brief-help-message-function - (or (symbolp ediff-brief-help-message-function) - (consp ediff-brief-help-message-function))) - (funcall ediff-brief-help-message-function)) - ((stringp ediff-brief-help-message-function) - ediff-brief-help-message-function) - ((ediff-multiframe-setup-p) ediff-brief-message-string) - (t ; long brief msg, not multiframe --- put in the middle - ediff-brief-message-string) - )) - (setq ediff-help-message (if ediff-use-long-help-message - ediff-long-help-message - ediff-brief-help-message)) - (run-hooks 'ediff-display-help-hook)) - ;;; Commands for working with Ediff @@ -770,8 +721,9 @@ Reestablish the default three-window display." control-frame (eq this-command 'ediff-quit)))) )) - (ediff-eval-in-buffer control-buf - (ediff-refresh-mode-lines)) + + (ediff-restore-highlighting) + (ediff-eval-in-buffer control-buf (ediff-refresh-mode-lines)) )) ;; this function returns to the window it was called from @@ -881,12 +833,13 @@ On a dumb terminal, switches between ASCII highlighting and no highlighting." ediff-highlight-all-diffs t))) (if (and ediff-use-faces ediff-highlight-all-diffs) - (ediff-color-background-regions) - (ediff-color-background-regions 'unhighlight)) + (ediff-paint-background-regions) + (ediff-paint-background-regions 'unhighlight)) (ediff-unselect-and-select-difference ediff-current-difference 'select-only)) ) + (defun ediff-toggle-autorefine () "Toggle auto-refine mode." @@ -1033,7 +986,10 @@ of the current buffer." (file-writable-p file) (or (file-exists-p (concat file ",v")) - (file-exists-p (concat "RCS/" file ",v"))) + (file-exists-p (concat (file-name-directory file) + "RCS/" + (file-name-nondirectory file) + ",v"))) )) (defun ediff-file-checked-in-p (file) (and (stringp file) @@ -2188,10 +2144,17 @@ temporarily reverses the meaning of this variable." (if (ediff-overlayp overl) (ediff-delete-overlay overl)))) ediff-narrow-bounds) - + ;; restore buffer mode line id's in buffer-A/B/C (let ((control-buffer ediff-control-buffer) - (meta-buffer ediff-meta-buffer)) + (meta-buffer ediff-meta-buffer) + ;; suitable working frame + (warp-frame (if (and (ediff-window-display-p) (eq ediff-grab-mouse t)) + (cond ((window-live-p ediff-window-A) + (window-frame ediff-window-A)) + ((window-live-p ediff-window-B) + (window-frame ediff-window-B)) + (t (next-frame)))))) (condition-case nil (ediff-eval-in-buffer ediff-buffer-A (setq ediff-this-buffer-ediff-sessions @@ -2233,6 +2196,14 @@ temporarily reverses the meaning of this variable." (ediff-update-registry) ;; restore state of buffers to what it was before ediff (ediff-restore-protected-variables) + + ;; If the user interrupts (canceling saving the merge buffer), continue + ;; normally. + (condition-case nil + (if (ediff-merge-job) + (run-hooks 'ediff-quit-merge-hook)) + (quit)) + ;; good place to kill buffers A/B/C (run-hooks 'ediff-cleanup-hook) (let ((ediff-keep-variants ediff-keep-variants)) @@ -2242,6 +2213,20 @@ temporarily reverses the meaning of this variable." (run-hooks 'ediff-quit-hook) (ediff-cleanup-meta-buffer meta-buffer) + + ;; warp mouse into a working window + (setq warp-frame ; if mouse is over a reasonable frame, use it + (cond ((and ediff-xemacs-p (window-live-p (car (mouse-position)))) + (window-frame (car (mouse-position)))) + ((frame-live-p (car (mouse-position))) + (car (mouse-position))) + (t warp-frame))) + (if (frame-live-p warp-frame) + (set-mouse-position (if ediff-emacs-p + warp-frame + (frame-selected-window warp-frame)) + 2 1)) + (if (ediff-buffer-live-p meta-buffer) (ediff-show-meta-buffer meta-buffer)) )) @@ -2290,7 +2275,7 @@ temporarily reverses the meaning of this variable." (or (ediff-get-visible-buffer-window buff-A) (progn (if (ediff-get-visible-buffer-window buff-B) - (split-window-vertically)) + (funcall ediff-split-window-function)) (switch-to-buffer buff-A))) (error)) (if three-way-job @@ -2299,7 +2284,7 @@ temporarily reverses the meaning of this variable." (progn (if (or (ediff-get-visible-buffer-window buff-A) (ediff-get-visible-buffer-window buff-B)) - (split-window-vertically)) + (funcall ediff-split-window-function)) (switch-to-buffer buff-C) (balance-windows))) (error))) @@ -2337,6 +2322,52 @@ buffer in another session as well." (buffer-name ediff-buffer-C))))) (ediff-kill-buffer-carefully ediff-buffer-C)))) +(defun ediff-maybe-save-and-delete-merge () + "Default hook to run on quitting a merge job. +If `ediff-autostore-merges' is nil, this does nothing. +If it is t, it saves the merge buffer in the file `ediff-merge-store-file' +or asks the user, if the latter is nil. It then then asks the user whether to +delete the merge buffer. +If `ediff-autostore-merges' is neither nil nor t, the merge buffer is saved +only if this merge job is part of a group, i.e., was invoked from within +`ediff-merge-directories', `ediff-merge-directory-revisions', and such." + (let ((merge-store-file ediff-merge-store-file)) + (if ediff-autostore-merges + (cond ((stringp ediff-merge-store-file) + ;; store, ask to delete + (ediff-write-merge-buffer-then-kill + ediff-buffer-C merge-store-file 'show-file)) + ((eq ediff-autostore-merges t) + ;; ask for file name + (setq merge-store-file + (read-file-name "Save the result of the merge in: ")) + (ediff-write-merge-buffer-then-kill + ediff-buffer-C merge-store-file)) + ((ediff-eval-in-buffer ediff-meta-buffer + (ediff-merge-metajob)) + ;; This case shouldn't occur, as the parent metajob must pass on + ;; a file name, ediff-merge-store-file, where to save the result + ;; of the merge. + ;; Ask where to save anyway--will decide what to do here later. + (setq merge-store-file + (read-file-name "The result of the merge goes into: ")) + (ediff-write-merge-buffer-then-kill + ediff-buffer-C merge-store-file)))) + )) + +(defun ediff-write-merge-buffer-then-kill (buf file &optional show-file) + (ediff-eval-in-buffer buf + (if (or (not (file-exists-p file)) + (y-or-n-p (format "File %s exists, overwrite? " file))) + (progn + (write-region (point-min) (point-max) file) + (if show-file + (progn + (message "Merge buffer saved in: %s" file) + (sit-for 2))) + (if (y-or-n-p "Merge buffer saved in file. Now kill the buffer? ") + (ediff-kill-buffer-carefully buf)))))) + ;; The default way of suspending Ediff. ;; Buries Ediff buffers, kills all windows. (defun ediff-default-suspend-function () @@ -2583,8 +2614,7 @@ Hit \\[ediff-recenter] to reset the windows afterward." (setq ediff-current-difference n) ) ; end protected section - (ediff-eval-in-buffer control-buf - (ediff-refresh-mode-lines)) + (ediff-eval-in-buffer control-buf (ediff-refresh-mode-lines)) ))) @@ -2618,7 +2648,6 @@ Hit \\[ediff-recenter] to reset the windows afterward." prompt (cond (default-file (concat " (default " default-file "):")) - ;;((string-match "[?:!,;][ \t]*$" prompt) "") (t (concat " (default " default-dir "):")))) default-dir (or default-file default-dir) @@ -2673,7 +2702,7 @@ Hit \\[ediff-recenter] to reset the windows afterward." nil ; don't append---erase 'no-message) (set-file-modes f ediff-temp-file-mode) - f))) + (ediff-convert-standard-filename (expand-file-name f))))) ;; Quote metacharacters (using \) when executing diff in Unix, but not in ;; EMX OS/2 @@ -2796,6 +2825,108 @@ Without an argument, it saves customized diff argument, if available (ediff-reset-mouse ediff-control-frame)) (if (window-live-p ediff-control-window) (select-window ediff-control-window))) + + +(defun ediff-inferior-compare-regions () + "Compare regions in an active Ediff session. +Like ediff-regions-linewise but is called from under an active Ediff session on +the files that belong to that session. + +After quitting the session invoked via this function, type C-l to the parent +Ediff Control Panel to restore highlighting." + (interactive) + (let ((answer "") + (possibilities (list ?A ?B ?C)) + begA begB endA endB bufA bufB) + + (cond ((ediff-merge-job) + (setq bufB ediff-buffer-C) + (while (cond ((memq answer '(?A ?a)) + (setq bufA ediff-buffer-A) + nil) + ((memq answer '(?B ?b)) + (setq bufA ediff-buffer-B) + nil) + ((equal answer "")) + (t (beep 1) + (message "Valid answers are A or B") + (sit-for 2) + t)) + (let ((cursor-in-echo-area t)) + (message "Which buffer to compare to the merge buffer (A/B)? ") + (setq answer (read-char-exclusive))))) + + ((ediff-3way-comparison-job) + (while (cond ((memq answer possibilities) + (setq possibilities (delq answer possibilities)) + (setq bufA + (eval + (intern (format "ediff-buffer-%c" answer)))) + nil) + ((equal answer "")) + (t (beep 1) + (message + "Valid answers are %s" + (mapconcat 'char-to-string possibilities " or ")) + (sit-for 2) + t)) + (let ((cursor-in-echo-area t)) + (message "Enter the 1st buffer you want to compare (%s): " + (mapconcat 'char-to-string possibilities "/")) + (setq answer (capitalize (read-char-exclusive))))) + (setq answer "") ; silence error msg + (while (cond ((memq answer possibilities) + (setq possibilities (delq answer possibilities)) + (setq bufB + (eval + (intern (format "ediff-buffer-%c" answer)))) + nil) + ((equal answer "")) + (t (beep 1) + (message + "Valid answers are %s" + (mapconcat 'char-to-string possibilities " or ")) + (sit-for 2) + t)) + (let ((cursor-in-echo-area t)) + (message "Enter the 2nd buffer you want to compare (%s): " + (mapconcat 'char-to-string possibilities "/")) + (setq answer (capitalize (read-char-exclusive)))))) + (t ; 2way comparison + (setq bufA ediff-buffer-A + bufB ediff-buffer-B))) + + (ediff-eval-in-buffer bufA + (setq begA (region-beginning) + endA (region-end)) + (goto-char begA) + (beginning-of-line) + (setq begA (point)) + (goto-char endA) + (end-of-line) + (or (eobp) (forward-char)) ; include the newline char + (setq endA (point))) + (ediff-eval-in-buffer bufB + (setq begB (region-beginning) + endB (region-end)) + (goto-char begB) + (beginning-of-line) + (setq begB (point)) + (goto-char endB) + (end-of-line) + (or (eobp) (forward-char)) ; include the newline char + (setq endB (point))) + + (ediff-unselect-and-select-difference + ediff-current-difference 'unselect-only) + (ediff-paint-background-regions 'unhighlight) + + (ediff-regions-internal + bufA begA endA bufB begB endB + nil ; startup hook + 'ediff-regions-linewise ; job name + nil) ; no word mode + )) @@ -2893,68 +3024,16 @@ Without an argument, it saves customized diff argument, if available )) +;; Restore highlighting to what it should be according to ediff-use-faces, +;; ediff-highlighting-style, and ediff-highlight-all-diffs variables. +(defun ediff-restore-highlighting (&optional ctl-buf) + (ediff-eval-in-buffer (or ctl-buf (current-buffer)) + (if (and (ediff-has-face-support-p) + ediff-use-faces + ediff-highlight-all-diffs) + (ediff-paint-background-regions)) + (ediff-select-difference ediff-current-difference))) -(defun ediff-highlight-diff-in-one-buffer (n buf-type) - (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) - (let* ((buff (ediff-get-buffer buf-type)) - (last (ediff-eval-in-buffer buff (point-max))) - (begin (ediff-get-diff-posn buf-type 'beg n)) - (end (ediff-get-diff-posn buf-type 'end n)) - (xtra (if (equal begin end) 1 0)) - (end-hilit (min last (+ end xtra))) - (current-diff-overlay - (symbol-value - (intern (format "ediff-current-diff-overlay-%S" buf-type)))) - ) - - (if ediff-xemacs-p - (ediff-move-overlay current-diff-overlay begin end-hilit) - (ediff-move-overlay current-diff-overlay begin end-hilit buff)) - ;; giving priority of 0 and then changing it may look funny, but - ;; this overcomes an obscure Emacs bug. - (ediff-overlay-put current-diff-overlay 'priority 0) - (ediff-overlay-put current-diff-overlay 'priority - (ediff-highest-priority begin end-hilit buff)) - (ediff-overlay-put current-diff-overlay 'ediff-diff-num n) - - ;; unhighlight the background overlay for diff n so it won't - ;; interfere with the current diff overlay - (ediff-set-overlay-face (ediff-get-diff-overlay n buf-type) nil) - ))) - - -(defun ediff-unhighlight-diff-in-one-buffer (buf-type) - (if (ediff-buffer-live-p (ediff-get-buffer buf-type)) - (let ((current-diff-overlay - (symbol-value - (intern (format "ediff-current-diff-overlay-%S" buf-type)))) - (overlay - (ediff-get-diff-overlay ediff-current-difference buf-type)) - ) - - (ediff-move-overlay current-diff-overlay 1 1) - - ;; rehighlight the overlay in the background of the - ;; current difference region - (ediff-set-overlay-face - overlay - (if (and (ediff-has-face-support-p) - ediff-use-faces ediff-highlight-all-diffs) - (ediff-background-face buf-type ediff-current-difference))) - ))) - -(defun ediff-unhighlight-diffs-totally-in-one-buffer (buf-type) - (ediff-unselect-and-select-difference -1) - (if (and (ediff-has-face-support-p) ediff-use-faces) - (let* ((inhibit-quit t) - (current-diff-overlay-var - (intern (format "ediff-current-diff-overlay-%S" buf-type))) - (current-diff-overlay (symbol-value current-diff-overlay-var))) - (ediff-color-background-regions 'unhighlight) - (if (ediff-overlayp current-diff-overlay) - (ediff-delete-overlay current-diff-overlay)) - (set current-diff-overlay-var nil) - ))) ;; null out difference overlays so they won't slow down future @@ -2973,58 +3052,10 @@ Without an argument, it saves customized diff argument, if available ;; allow them to be garbage collected (set vec-var nil)) -(defun ediff-color-background-regions (&optional unhighlight) - (ediff-color-background-regions-in-one-buffer - 'A unhighlight) - (ediff-color-background-regions-in-one-buffer - 'B unhighlight) - (ediff-color-background-regions-in-one-buffer - 'C unhighlight) - (ediff-color-background-regions-in-one-buffer - 'Ancestor unhighlight)) - -(defun ediff-color-background-regions-in-one-buffer (buf-type unhighlight) - (let ((diff-vector - (eval (intern (format "ediff-difference-vector-%S" buf-type)))) - overl diff-num) - (mapcar (function - (lambda (rec) - (setq overl (ediff-get-diff-overlay-from-diff-record rec) - diff-num (ediff-overlay-get overl 'ediff-diff-num)) - (ediff-set-overlay-face - overl - (if (not unhighlight) - (ediff-background-face buf-type diff-num)) - ))) - diff-vector))) ;;; Misc -;; These two functions are here to neutralize XEmacs unwillingless to -;; handle overlays whose buffers were deleted. -(defun ediff-move-overlay (overlay beg end &optional buffer) - "Calls `move-overlay' in Emacs and `set-extent-endpoints' in Lemacs. -Checks if overlay's buffer exists before actually doing the move." - (let ((buf (and overlay (ediff-overlay-buffer overlay)))) - (if (ediff-buffer-live-p buf) - (if ediff-xemacs-p - (set-extent-endpoints overlay beg end) - (move-overlay overlay beg end buffer)) - ;; buffer's dead - (if overlay - (ediff-delete-overlay overlay))))) - -(defun ediff-overlay-put (overlay prop value) - "Calls `overlay-put' or `set-extent-property' depending on Emacs version. -Checks if overlay's buffer exists." - (if (ediff-buffer-live-p (ediff-overlay-buffer overlay)) - (if ediff-xemacs-p - (set-extent-property overlay prop value) - (overlay-put overlay prop value)) - (ediff-delete-overlay overlay))) - - ;; In Emacs, this just makes overlay. In the future, when Emacs will start ;; supporting sticky overlays, this function will make a sticky overlay. ;; BEG and END are expressions telling where overlay starts. @@ -3462,6 +3493,7 @@ Mail anyway? (y or n) ") ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-util) diff --git a/lisp/ediff-vers.el b/lisp/ediff-vers.el index 5730d52062..cec2d6f2cc 100644 --- a/lisp/ediff-vers.el +++ b/lisp/ediff-vers.el @@ -31,15 +31,16 @@ (defvar cvs-program) (defvar cvs-cookie-handle) -(eval-when-compile - (load "pcl-cvs" 'noerror) - (load "rcs" 'noerror) - (load "generic-sc" 'noerror) - (load "vc" 'noerror)) +(and noninteractive + (eval-when-compile + (load "pcl-cvs" 'noerror) + (load "rcs" 'noerror) + (load "generic-sc" 'noerror) + (load "vc" 'noerror))) ;; end pacifier ;; VC.el support -(defun vc-ediff-internal (rev1 rev2 &optional startup-hooks) +(defun ediff-vc-internal (rev1 rev2 &optional startup-hooks) ;; Run Ediff on versions of the current buffer. ;; If REV2 is "" then compare current buffer with REV1. ;; If the current buffer is named `F', the version is named `F.~REV~'. @@ -103,7 +104,7 @@ (erase-buffer)) buf)) -(defun rcs-ediff-internal (rev1 rev2 &optional startup-hooks) +(defun ediff-rcs-internal (rev1 rev2 &optional startup-hooks) ;; Run Ediff on versions of the current buffer. ;; If REV2 is "" then use current buffer. (let ((rev2buf (if (string= rev2 "") @@ -124,7 +125,7 @@ (eval "main/LATEST")) (t (eval "")))) -(defun generic-sc-ediff-internal (rev1 rev2 &optional startup-hooks) +(defun ediff-generic-sc-internal (rev1 rev2 &optional startup-hooks) ;; Run Ediff on versions of the current buffer. ;; If REV2 is "" then compare current buffer with REV1. ;; If the current buffer is named `F', the version is named `F.~REV~'. @@ -144,7 +145,7 @@ ;;; Merge with Version Control -(defun vc-ediff-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks) +(defun ediff-vc-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks) ;; If ANCESTOR-REV non-nil, merge with ancestor (let (buf1 buf2 ancestor-buf) (save-excursion @@ -177,7 +178,7 @@ (ediff-merge-buffers buf1 buf2 startup-hooks 'ediff-merge-revisions)) )) -(defun rcs-ediff-merge-internal (rev1 rev2 ancestor-rev +(defun ediff-rcs-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks) ;; If ANCESTOR-REV non-nil, merge with ancestor (let (buf1 buf2 ancestor-buf) @@ -197,7 +198,7 @@ startup-hooks 'ediff-merge-revisions-with-ancestor) (ediff-merge-buffers buf1 buf2 startup-hooks 'ediff-merge-revisions)))) -(defun generic-sc-ediff-merge-internal (rev1 rev2 ancestor-rev +(defun ediff-generic-sc-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks) ;; If ANCESTOR-REV non-nil, merge with ancestor (let (buf1 buf2 ancestor-buf) @@ -224,7 +225,7 @@ ;; PCL-CVS.el support -(defun pcl-cvs-ediff-internal (rev1 rev2 &optional startup-hooks) +(defun ediff-pcl-cvs-internal (rev1 rev2 &optional startup-hooks) ;; Run Ediff on a pair of revisions of the current buffer. ;; If REV1 is "", use the latest revision. ;; If REV2 is "", use the current buffer as the second file to compare. @@ -251,7 +252,7 @@ ;; This function is the standard Ediff's interface to pcl-cvs. ;; Works like with other interfaces: runs ediff on versions of the file in the ;; current buffer. -(defun pcl-cvs-ediff-merge-internal (rev1 rev2 ancestor-rev +(defun ediff-pcl-cvs-merge-internal (rev1 rev2 ancestor-rev &optional startup-hooks) ;; Ediff-merge appropriate revisions of the selected file. ;; If REV1 is "" then use the latest revision. @@ -358,6 +359,7 @@ ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-vers) diff --git a/lisp/ediff-wind.el b/lisp/ediff-wind.el index f4033cf5b8..58cae39a19 100644 --- a/lisp/ediff-wind.el +++ b/lisp/ediff-wind.el @@ -853,7 +853,7 @@ into icons, regardless of the window manager.") ;; 1 more line for the modeline (setq lines (1+ (count-lines (point-min) (point-max))) fheight lines - fwidth (+ (ediff-help-message-line-length) 2) + fwidth (+ (ediff-help-message-line-length) 1) adjusted-parameters (append (list ;; possibly change surrogate minibuffer (cons 'minibuffer @@ -1061,7 +1061,7 @@ It assumes that it is called from within the control buffer." (setq mode-line-format (list (if (ediff-narrow-control-frame-p) " " "-- ") mode-line-buffer-identification - " Quick Help")) + " Quick Help")) ;; control buffer id (setq mode-line-buffer-identification (if (ediff-narrow-control-frame-p) @@ -1199,6 +1199,7 @@ It assumes that it is called from within the control buffer." ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff-wind) diff --git a/lisp/ediff.el b/lisp/ediff.el index d071c72114..be9c1d143d 100644 --- a/lisp/ediff.el +++ b/lisp/ediff.el @@ -6,8 +6,8 @@ ;; Created: February 2, 1994 ;; Keywords: comparing, merging, patching, version control. -(defconst ediff-version "2.61" "The current version of Ediff") -(defconst ediff-date "June 10, 1996" "Date of last update") +(defconst ediff-version "2.63" "The current version of Ediff") +(defconst ediff-date "September 12, 1996" "Date of last update") ;; This file is part of GNU Emacs. @@ -110,11 +110,13 @@ ;; ediff-mult is always required, because of the registry stuff (require 'ediff-mult) -(eval-when-compile - (load "dired") - (load-file "./ediff-ptch.el") - (load-file "./ediff-vers.el") - (load "pcl-cvs" 'noerror)) +(and noninteractive + (eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (load-library "dired") + (load-file "ediff-ptch.el") + (load-file "ediff-vers.el") + (load "pcl-cvs" 'noerror)))) (defvar ediff-use-last-dir nil "*If t, Ediff uses previous directory as default when reading file name.") @@ -127,6 +129,8 @@ "Last directory used by an Ediff command for file-C.") (defvar ediff-last-dir-ancestor nil "Last directory used by an Ediff command for the ancestor file.") +(defvar ediff-last-merge-autostore-dir + "Last directory used by an Ediff command as the output directory for merge.") ;; Some defvars to reduce the number of compiler warnings (defvar cvs-cookie-handle) @@ -562,7 +566,7 @@ can be used to filter out certain file names." The second argument, REGEXP, is a regular expression that filters the file names. Only the files that are under revision control are taken into account." (interactive - (let ((dir-A (ediff-get-default-directory-name))) + (let* ((dir-A (ediff-get-default-directory-name))) (list (ediff-read-file-name "Directory to merge with revisions:" dir-A nil) (read-string "Filter through regular expression: " @@ -581,7 +585,7 @@ names. Only the files that are under revision control are taken into account." The second argument, REGEXP, is a regular expression that filters the file names. Only the files that are under revision control are taken into account." (interactive - (let ((dir-A (ediff-get-default-directory-name))) + (let* ((dir-A (ediff-get-default-directory-name))) (list (ediff-read-file-name "Directory to merge with revisions and ancestors:" dir-A nil) (read-string "Filter through regular expression: " @@ -605,8 +609,8 @@ names. Only the files that are under revision control are taken into account." ;; The third argument, REGEXP, is a regular expression that can be used to ;; filter out certain file names. ;; JOBNAME is the symbol indicating the meta-job to be performed. -(defun ediff-directories-internal (dir1 dir2 dir3 regexp - action jobname +;; MERGE-DIR is the directory in which to store merged files. +(defun ediff-directories-internal (dir1 dir2 dir3 regexp action jobname &optional startup-hooks) ;; ediff-read-file-name is set to attach a previously entered file name if ;; the currently entered file is a directory. This code takes care of that. @@ -626,9 +630,31 @@ names. Only the files that are under revision control are taken into account." (error "Directories B and C are the same: %s" dir1))) (let (diffs ; var where ediff-intersect-directories returns the diff list + merge-autostore-dir file-list meta-buf) + (if (and ediff-autostore-merges (ediff-merge-metajob jobname)) + (setq merge-autostore-dir + (ediff-read-file-name "Directory to save merged files:" + (if ediff-use-last-dir + ediff-last-merge-autostore-dir + (ediff-strip-last-dir dir1)) + nil))) + ;; verify we are not merging into an orig directory + (if (stringp merge-autostore-dir) + (cond ((and (stringp dir1) (string= merge-autostore-dir dir1)) + (or (y-or-n-p "Merge directory same as directory A, sure? ") + (error "Directory merge aborted"))) + ((and (stringp dir2) (string= merge-autostore-dir dir2)) + (or (y-or-n-p "Merge directory same as directory B, sure? ") + (error "Directory merge aborted"))) + ((and (stringp dir3) (string= merge-autostore-dir dir3)) + (or (y-or-n-p + "Merge directory same as ancestor directory, sure? ") + (error "Directory merge aborted"))))) + (setq file-list (ediff-intersect-directories - jobname 'diffs regexp dir1 dir2 dir3)) + jobname 'diffs + regexp dir1 dir2 dir3 merge-autostore-dir)) (setq startup-hooks ;; this sets various vars in the meta buffer inside ;; ediff-prepare-meta-buffer @@ -651,9 +677,26 @@ names. Only the files that are under revision control are taken into account." (defun ediff-directory-revisions-internal (dir1 regexp action jobname &optional startup-hooks) (setq dir1 (if (file-directory-p dir1) dir1 (file-name-directory dir1))) - (let (file-list meta-buf) + + (let (file-list meta-buf merge-autostore-dir) + (if (and ediff-autostore-merges (ediff-merge-metajob jobname)) + (setq merge-autostore-dir + (ediff-read-file-name "Directory to save merged files:" + (if ediff-use-last-dir + ediff-last-merge-autostore-dir + (ediff-strip-last-dir dir1)) + nil))) + ;; verify merge-autostore-dir != dir1 + (if (and (stringp merge-autostore-dir) + (stringp dir1) + (string= merge-autostore-dir dir1)) + (or (y-or-n-p + "Directory for saving merges is the same as directory A. Sure? ") + (error "Merge of directory revisions aborted"))) + (setq file-list - (ediff-get-directory-files-under-revision jobname regexp dir1)) + (ediff-get-directory-files-under-revision + jobname regexp dir1 merge-autostore-dir)) (setq startup-hooks ;; this sets various vars in the meta buffer inside ;; ediff-prepare-meta-buffer @@ -804,7 +847,6 @@ lines. For small regions, use `ediff-regions-wordwise'." (setq reg-B-beg (region-beginning) reg-B-end (region-end)) ;; enlarge the region to hold full lines - (goto-char reg-A-beg) (goto-char reg-B-beg) (beginning-of-line) (setq reg-B-beg (point)) @@ -1052,7 +1094,7 @@ buffer." (ediff-load-version-control) ;; ancestor-revision=nil (funcall - (intern (format "%S-ediff-merge-internal" ediff-version-control-package)) + (intern (format "ediff-%S-merge-internal" ediff-version-control-package)) rev1 rev2 nil startup-hooks))) @@ -1084,7 +1126,7 @@ buffer." (file-name-nondirectory file) "current buffer")))) (ediff-load-version-control) (funcall - (intern (format "%S-ediff-merge-internal" ediff-version-control-package)) + (intern (format "ediff-%S-merge-internal" ediff-version-control-package)) rev1 rev2 ancestor-rev startup-hooks))) ;;;###autoload @@ -1168,7 +1210,7 @@ buffer. Use `vc.el' or `rcs.el' depending on `ediff-version-control-package'." (file-name-nondirectory file) "current buffer")))) (ediff-load-version-control) (funcall - (intern (format "%S-ediff-internal" ediff-version-control-package)) + (intern (format "ediff-%S-internal" ediff-version-control-package)) rev1 rev2 startup-hooks) )) @@ -1198,8 +1240,9 @@ When called interactively, displays the version." ;;;###autoload -(defun ediff-documentation () - "Display Ediff's manual." +(defun ediff-documentation (&optional node) + "Display Ediff's manual. +With optional NODE, goes to that node." (interactive) (let ((ctl-window ediff-control-window) (ctl-buf ediff-control-buffer)) @@ -1209,15 +1252,13 @@ When called interactively, displays the version." (progn (pop-to-buffer (get-buffer-create "*info*")) (info (if ediff-xemacs-p "ediff.info" "ediff")) - (message "Type `i' to search for a specific topic")) + (if node + (Info-goto-node node) + (message "Type `i' to search for a specific topic")) + (raise-frame (selected-frame))) (error (beep 1) (with-output-to-temp-buffer ediff-msg-buffer - (princ (format " -The Info file for Ediff does not seem to be installed. - -This file is part of the distribution of %sEmacs. -Please contact your system administrator. " - (if ediff-xemacs-p "X" "")))) + (princ ediff-BAD-INFO)) (if (window-live-p ctl-window) (progn (select-window ctl-window) @@ -1229,6 +1270,7 @@ Please contact your system administrator. " ;;; Local Variables: ;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun) ;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-eval-in-buffer 'edebug-form-spec '(form body)) ;;; End: (provide 'ediff) diff --git a/lisp/emulation/viper-util.el b/lisp/emulation/viper-util.el index baf8c88925..09e2787cca 100644 --- a/lisp/emulation/viper-util.el +++ b/lisp/emulation/viper-util.el @@ -553,7 +553,11 @@ to write a custom function, similar to `vip-ex-nontrivial-find-file-unix'." (setq tmp (cdr tmp))) (reverse (apply 'append tmp2)))) - +(defun vip-convert-standard-file-name (fname) + (if vip-emacs-p + (convert-standard-filename fname) + ;; hopefully, XEmacs adds this functionality + fname)) diff --git a/lisp/emulation/viper.el b/lisp/emulation/viper.el index 5711d448a2..f3ede94644 100644 --- a/lisp/emulation/viper.el +++ b/lisp/emulation/viper.el @@ -821,7 +821,7 @@ These buffers can be cycled through via :R and :P commands.") (defvar vip-always t "t means, arrange that vi-state will be a default.") -(defvar vip-custom-file-name (convert-standard-filename "~/.vip") +(defvar vip-custom-file-name (vip-convert-standard-file-name "~/.vip") "Viper customisation file. This variable must be set _before_ loading Viper.") @@ -2847,10 +2847,8 @@ Undo previous insertion and inserts new." (setq vip-cted t) (if vip-electric-mode (indent-according-to-mode) - (indent-to col)) - )) - (vip-change-state-to-insert) - )))) + (indent-to col)))) + (vip-change-state-to-insert))))) (defun vip-Open-line (arg) "Open line above." @@ -3851,8 +3849,9 @@ controlled by the sign of prefix numeric value." (defun vip-paren-match (arg) "Go to the matching parenthesis." (interactive "P") + (vip-leave-region-active) (let ((com (vip-getcom arg)) - anchor-point) + parse-sexp-ignore-comments anchor-point) (if (integerp arg) (if (or (> arg 99) (< arg 1)) (error "Prefix must be between 1 and 99") @@ -4904,7 +4903,9 @@ One can use `` and '' to temporarily jump 1 step back." vip-open-line vip-Open-line vip-replace-state-exit-cmd)) (indent-to-left-margin)) - (newline 1) + ;; use \n instead of newline, or else will move the insert point + ;;(newline 1) + (insert "\n") (if vip-auto-indent (progn (setq vip-cted t) -- 2.39.2