X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/92c51e075e8bc9c2ace8487bfc42f23389d09b73..0b64a3da3a1673936bb61a5a9faa103640c66cf9:/lisp/ediff-diff.el diff --git a/lisp/ediff-diff.el b/lisp/ediff-diff.el index 31e126c229..4859175707 100644 --- a/lisp/ediff-diff.el +++ b/lisp/ediff-diff.el @@ -1,6 +1,6 @@ ;;; ediff-diff.el --- diff-related utilities -;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. ;; Author: Michael Kifer @@ -23,10 +23,29 @@ ;;; Code: +(provide 'ediff-diff) + +;; compiler pacifier +(defvar ediff-default-variant) + +(eval-when-compile + (let ((load-path (cons (expand-file-name ".") load-path))) + (or (featurep 'ediff-init) + (load "ediff-init.el" nil nil 'nosuffix)) + (or (featurep 'ediff-util) + (load "ediff-util.el" nil nil 'nosuffix)) + )) +;; end pacifier + (require 'ediff-init) +(defgroup ediff-diff nil + "Diff related utilities" + :prefix "ediff-" + :group 'ediff) -(defvar ediff-shell + +(defcustom ediff-shell (cond ((eq system-type 'emx) "cmd") ; OS/2 ((memq system-type '(ms-dos windows-nt windows-95)) shell-file-name) ; no standard name on MS-DOS @@ -36,37 +55,57 @@ .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.") +to a shell that you are not using or, better, fix your shell's startup file." + :type 'string + :group 'ediff-diff) +(defcustom ediff-cmp-program "cmp" + "*Utility to use to determine if two files are identical. +It must return code 0, if its arguments are identical files." + :type 'string + :group 'ediff-diff) -(defvar ediff-diff-program "diff" - "*Program to use for generating the differential of the two files.") -(defvar ediff-diff-options "" +(defcustom ediff-diff-program "diff" + "*Program to use for generating the differential of the two files." + :type 'string + :group 'ediff-diff) +(defcustom ediff-diff-options "" "*Options to pass to `ediff-diff-program'. If diff\(1\) is used as `ediff-diff-program', then the most useful options are `-w', to ignore space, and `-i', to ignore case of letters. -At present, the option `-c' is ignored, since Ediff doesn't understand this -type of output.") +At present, the option `-c' is not allowed." + :type 'string + :group 'ediff-diff) -(defvar ediff-custom-diff-program ediff-diff-program +(defcustom ediff-custom-diff-program ediff-diff-program "*Program to use for generating custom diff output for saving it in a file. -This output is not used by Ediff internally.") -(defvar ediff-custom-diff-options "-c" - "*Options to pass to `ediff-custom-diff-program'.") +This output is not used by Ediff internally." + :type 'string + :group 'ediff-diff) +(defcustom ediff-custom-diff-options "-c" + "*Options to pass to `ediff-custom-diff-program'." + :type 'string + :group 'ediff-diff) ;;; Support for diff3 (defvar ediff-match-diff3-line "^====\\(.?\\)$" "Pattern to match lines produced by diff3 that describe differences.") -(defvar ediff-diff3-program "diff3" +(defcustom ediff-diff3-program "diff3" "*Program to be used for three-way comparison. -Must produce output compatible with Unix's diff3 program.") -(defvar ediff-diff3-options "" - "*Options to pass to `ediff-diff3-program'.") -(defvar ediff-diff3-ok-lines-regexp +Must produce output compatible with Unix's diff3 program." + :type 'string + :group 'ediff-diff) +(defcustom ediff-diff3-options "" + "*Options to pass to `ediff-diff3-program'." + :type 'string + :group 'ediff-diff) +(defcustom ediff-diff3-ok-lines-regexp "^\\([1-3]:\\|====\\| \\|.*Warning *:\\|.*No newline\\|.*missing newline\\|^\C-m$\\)" "*Regexp that matches normal output lines from `ediff-diff3-program'. -Lines that do not match are assumed to be error messages.") +Lines that do not match are assumed to be error messages." + :type 'regexp + :group 'ediff-diff) ;; keeps the status of the current diff in 3-way jobs. ;; the status can be =diff(A), =diff(B), or =diff(A+B) @@ -94,14 +133,24 @@ Use `setq-default' if setting it in .emacs") ;;; General (defvar ediff-diff-ok-lines-regexp - "^\\([0-9,]+[acd][0-9,]+$\\|[<>] \\|---\\|.*Warning *:\\|.*No +newline\\|.*missing +newline\\|^\C-m$\\)" + (concat + "^\\(" + "[0-9,]+[acd][0-9,]+\C-m?$" + "\\|[<>] " + "\\|---" + "\\|.*Warning *:" + "\\|.*No +newline" + "\\|.*missing +newline" + "\\|^\C-m?$" + "\\)") "Regexp that matches normal output lines from `ediff-diff-program'. This is mostly lifted from Emerge, except that Ediff also considers warnings and `Missing newline'-type messages 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 "$")) +(defvar ediff-match-diff-line + (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)")) + (concat "^" x "\\([acd]\\)" x "\C-m?$")) "Pattern to match lines produced by diff that describe differences.") (ediff-defvar-local ediff-setup-diff-regions-function nil @@ -123,9 +172,8 @@ one optional arguments, diff-number to refine.") ;; ediff-setup-diff-regions-function, which can also have the value ;; ediff-setup-diff-regions3, which takes 4 arguments. (defun ediff-setup-diff-regions (file-A file-B file-C) -;;; ;; Force all minibuffers to display ediff's messages. -;;; ;; When xemacs implements minibufferless frames, this won't be necessary -;;; (if ediff-xemacs-p (setq synchronize-minibuffers t)) + (if (string-match "c" ediff-diff-options) + (error "Option `-c' is not allowed in `ediff-diff-options'")) ;; create, if it doesn't exist (or (ediff-buffer-live-p ediff-diff-buffer) @@ -175,9 +223,8 @@ one optional arguments, diff-number to refine.") diff-buffer 'synchronize ediff-diff-options file1 file2) - ;;(message "Computing differences ... done") (message "") - (ediff-eval-in-buffer diff-buffer + (ediff-with-current-buffer diff-buffer (buffer-size)))))) @@ -248,15 +295,15 @@ one optional arguments, diff-number to refine.") (setq ediff-error-buffer (get-buffer-create (ediff-unique-buffer-name "*ediff-errors" "*")))) - (ediff-eval-in-buffer ediff-error-buffer + (ediff-with-current-buffer ediff-error-buffer (erase-buffer) - (insert (ediff-eval-in-buffer diff-buff (buffer-string))) + (insert (ediff-with-current-buffer diff-buff (buffer-string))) (goto-char (point-min)) (delete-matching-lines ok-regexp) (if (memq system-type '(vax-vms axp-vms)) (delete-matching-lines "^$"))) ;; If diff reports errors, show them then quit. - (if (/= 0 (ediff-eval-in-buffer ediff-error-buffer (buffer-size))) + (if (/= 0 (ediff-with-current-buffer ediff-error-buffer (buffer-size))) (let ((ctl-buf ediff-control-buffer) (error-buf ediff-error-buffer)) (ediff-skip-unsuitable-frames) @@ -293,15 +340,15 @@ one optional arguments, diff-number to refine.") (ediff-get-value-according-to-buffer-type 'B bounds)))) ;; reset point in buffers A/B/C - (ediff-eval-in-buffer A-buffer + (ediff-with-current-buffer A-buffer (goto-char (if shift-A shift-A (point-min)))) - (ediff-eval-in-buffer B-buffer + (ediff-with-current-buffer B-buffer (goto-char (if shift-B shift-B (point-min)))) (if (ediff-buffer-live-p C-buffer) - (ediff-eval-in-buffer C-buffer + (ediff-with-current-buffer C-buffer (goto-char (point-min)))) - (ediff-eval-in-buffer diff-buffer + (ediff-with-current-buffer diff-buffer (goto-char (point-min)) (while (re-search-forward ediff-match-diff-line nil t) (let* ((a-begin (string-to-int (buffer-substring (match-beginning 1) @@ -369,20 +416,20 @@ one optional arguments, diff-number to refine.") b-prev b-end c-prev c-end) ;; else convert lines to points - (ediff-eval-in-buffer A-buffer + (ediff-with-current-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)) - (ediff-eval-in-buffer B-buffer + (ediff-with-current-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)) (if (ediff-buffer-live-p C-buffer) - (ediff-eval-in-buffer C-buffer + (ediff-with-current-buffer C-buffer (forward-line (- c-begin c-prev)) (setq c-begin-pt (point)) (forward-line (- c-end c-begin)) @@ -412,7 +459,7 @@ one optional arguments, diff-number to refine.") ))) ))) - ))) ; end ediff-eval-in-buffer + ))) ; end ediff-with-current-buffer diff-list )) @@ -460,7 +507,7 @@ one optional arguments, diff-number to refine.") (setq total-diffs (length diff-list)) ;; shift, if necessary - (ediff-eval-in-buffer buff (setq pt-saved shift)) + (ediff-with-current-buffer buff (setq pt-saved shift)) (while diff-list (setq current-diff (1+ current-diff) @@ -489,12 +536,12 @@ one optional arguments, diff-number to refine.") ;; convert word numbers to points, if necessary (if (eq diff-list-type 'words) (progn - (ediff-eval-in-buffer buff (goto-char pt-saved)) + (ediff-with-current-buffer buff (goto-char pt-saved)) (setq begin (ediff-goto-word (1+ begin) buff) end (ediff-goto-word end buff 'end)) (if (> end limit) (setq end limit)) (if (> begin end) (setq begin end)) - (setq pt-saved (ediff-eval-in-buffer buff (point))))) + (setq pt-saved (ediff-with-current-buffer buff (point))))) (setq overlay (ediff-make-bullet-proof-overlay begin end buff)) (ediff-overlay-put overlay 'priority ediff-shadow-overlay-priority) @@ -518,7 +565,7 @@ one optional arguments, diff-number to refine.") (cdr diff-list)) ) ; while - (set (intern (format "ediff-difference-vector-%S" buf-type)) + (set (ediff-get-symbol-from-alist buf-type ediff-difference-vector-alist) (vconcat diff-overlay-list)) )) @@ -551,13 +598,7 @@ one optional arguments, diff-number to refine.") (whitespace-C (ediff-whitespace-diff-region-p n 'C)) cumulative-fine-diff-length) - (cond ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n 'A)) - ;; don't compute fine diffs if diff vector exists - (if (ediff-no-fine-diffs-p n) - ;;(ediff-message-if-verbose - (message - "Only white-space differences in region %d" (1+ n)))) - ;; If one of the regions is empty (or 2 in 3way comparison) + (cond ;; If one of the regions is empty (or 2 in 3way comparison) ;; then don't refine. ;; If the region happens to be entirely whitespace or empty then ;; mark as such. @@ -586,6 +627,20 @@ one optional arguments, diff-number to refine.") ;; if some regions are white and others don't, then mark as ;; non-white-space-only (ediff-mark-diff-as-space-only n nil))) + + ;; don't compute fine diffs if diff vector exists + ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n 'A)) + (if (ediff-no-fine-diffs-p n) + (message + "Only white-space differences in region %d %s" + (1+ n) + (cond ((eq (ediff-no-fine-diffs-p n) 'A) + "in buffers B & C") + ((eq (ediff-no-fine-diffs-p n) 'B) + "in buffers A & C") + ((eq (ediff-no-fine-diffs-p n) 'C) + "in buffers A & B") + (t ""))))) ;; don't compute fine diffs for this region ((eq flag 'skip) (or (ediff-get-fine-diff-vector n 'A) @@ -666,13 +721,15 @@ one optional arguments, diff-number to refine.") (ediff-message-if-verbose "Only white-space differences in region %d" (1+ n))) ((eq cumulative-fine-diff-length 0) - (ediff-mark-diff-as-space-only n t) (ediff-message-if-verbose "Only white-space differences in region %d %s" (1+ n) - (cond (whitespace-A "in buffers B & C") - (whitespace-B "in buffers A & C") - (whitespace-C "in buffers A & B")))) + (cond (whitespace-A (ediff-mark-diff-as-space-only n 'A) + "in buffers B & C") + (whitespace-B (ediff-mark-diff-as-space-only n 'B) + "in buffers A & C") + (whitespace-C (ediff-mark-diff-as-space-only n 'C) + "in buffers A & B")))) (t (ediff-mark-diff-as-space-only n nil))) ) @@ -716,14 +773,15 @@ one optional arguments, diff-number to refine.") (face (if default 'default (face-name - (intern (format "ediff-fine-diff-face-%S" buf-type))))) + (ediff-get-symbol-from-alist + buf-type ediff-fine-diff-face-alist)))) (priority (if default 0 (1+ (or (ediff-overlay-get (symbol-value - (intern - (format - "ediff-current-diff-overlay-%S" buf-type))) + (ediff-get-symbol-from-alist + buf-type + ediff-current-diff-overlay-alist)) 'priority) 0))))) (mapcar @@ -761,7 +819,7 @@ one optional arguments, diff-number to refine.") (ediff-clear-fine-differences-in-one-buffer region-num buf-type) (setq diff-list (cdr diff-list)) ; discard list type (words or points) - (ediff-eval-in-buffer buff (goto-char reg-start)) + (ediff-with-current-buffer buff (goto-char reg-start)) ;; if it is a combined merge then set overlays in buff C specially (if (and ediff-merge-job (eq buf-type 'C) @@ -864,18 +922,18 @@ one optional arguments, diff-number to refine.") (ediff-get-value-according-to-buffer-type 'C bounds))))) ;; reset point in buffers A, B, C - (ediff-eval-in-buffer A-buffer + (ediff-with-current-buffer A-buffer (goto-char (if shift-A shift-A (point-min)))) - (ediff-eval-in-buffer B-buffer + (ediff-with-current-buffer B-buffer (goto-char (if shift-B shift-B (point-min)))) (if three-way-comp - (ediff-eval-in-buffer C-buffer + (ediff-with-current-buffer C-buffer (goto-char (if shift-C shift-C (point-min))))) (if (ediff-buffer-live-p anc-buffer) - (ediff-eval-in-buffer anc-buffer + (ediff-with-current-buffer anc-buffer (goto-char (point-min)))) - (ediff-eval-in-buffer diff-buffer + (ediff-with-current-buffer diff-buffer (goto-char (point-min)) (while (re-search-forward ediff-match-diff3-line nil t) ;; leave point after matched line @@ -938,26 +996,26 @@ one optional arguments, diff-number to refine.") b-prev b-end c-prev c-end) ;; else convert lines to points - (ediff-eval-in-buffer A-buffer + (ediff-with-current-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)) - (ediff-eval-in-buffer B-buffer + (ediff-with-current-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)) - (ediff-eval-in-buffer C-buffer + (ediff-with-current-buffer C-buffer (forward-line (- c-begin c-prev)) (setq c-begin-pt (point)) (forward-line (- c-end c-begin)) (setq c-end-pt (point) c-prev c-end)) (if (ediff-buffer-live-p anc-buffer) - (ediff-eval-in-buffer anc-buffer + (ediff-with-current-buffer anc-buffer (forward-line (- c-or-anc-begin anc-prev)) (setq anc-begin-pt (point)) (forward-line (- c-or-anc-end c-or-anc-begin)) @@ -989,7 +1047,7 @@ one optional arguments, diff-number to refine.") ))) )) - ))) ; end ediff-eval-in-buffer + ))) ; end ediff-with-current-buffer diff-list )) @@ -997,11 +1055,6 @@ one optional arguments, diff-number to refine.") ;; File-C is either the third file to compare (in case of 3-way comparison) ;; or it is the ancestor file. (defun ediff-setup-diff-regions3 (file-A file-B file-C) - -;;; ;; force all minibuffers to display ediff's messages. -;;; ;; when xemacs implements minibufferless frames, this won't be necessary -;;; (if ediff-xemacs-p (setq synchronize-minibuffers t)) - (or (ediff-buffer-live-p ediff-diff-buffer) (setq ediff-diff-buffer (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*")))) @@ -1020,15 +1073,15 @@ one optional arguments, diff-number to refine.") ;; Execute PROGRAM asynchronously, unless OS/2, Windows-*, or DOS, or unless -;; SYNCH is non-nil. BUFFER must be a buffer object, and must be alive. All -;; arguments in ARGS must be strings. The first arg may be a blank string, in -;; which case we delete it from ARGS list. We also delete nil from args. -(defun ediff-exec-process (program buffer synch &rest args) - (let ((data (match-data))) - (if (string-match "^[ \t]*$" (car args)) ; delete blank string - (setq args (cdr args))) - (setq args (delq nil args)) ; delete nil from arguments - (setq args (ediff-split-string (mapconcat 'identity args " "))) +;; SYNCH is non-nil. BUFFER must be a buffer object, and must be alive. The +;; OPTIONS arg is a list of options to pass to PROGRAM. It may be a blank +;; string. All elements in FILES must be strings. We also delete nil from +;; args. +(defun ediff-exec-process (program buffer synch options &rest files) + (let ((data (match-data)) + args) + (setq args (append (split-string options) files)) + (setq args (delete "" (delq nil args))) ; delete nil and "" from arguments (unwind-protect (let ((directory default-directory) proc) @@ -1059,7 +1112,7 @@ one optional arguments, diff-number to refine.") ))) (store-match-data data)))) -;; This is shell-command-filter from simple.el in FSF Emacs. +;; This is shell-command-filter from simple.el in Emacs. ;; Copied here because XEmacs doesn't have it. (defun ediff-process-filter (proc string) ;; Do save-excursion by hand so that we can leave point numerically unchanged @@ -1146,7 +1199,7 @@ argument to `skip-chars-forward'." (let (sv-point string) (save-excursion (set-buffer in-buffer) - (setq string (buffer-substring beg end)) + (setq string (buffer-substring-no-properties beg end)) (set-buffer out-buffer) (erase-buffer) @@ -1160,7 +1213,7 @@ argument to `skip-chars-forward'." ;; different invocations (if control-buf (funcall - (ediff-eval-in-buffer control-buf ediff-forward-word-function)) + (ediff-with-current-buffer control-buf ediff-forward-word-function)) (funcall ediff-forward-word-function)) (setq sv-point (point)) (skip-chars-forward ediff-whitespace) @@ -1187,7 +1240,7 @@ argument to `skip-chars-forward'." (defun ediff-goto-word (n buf &optional flag) ;; remember val ediff-forward-word-function has in ctl buf (let ((fwd-word-fun ediff-forward-word-function)) - (ediff-eval-in-buffer buf + (ediff-with-current-buffer buf (skip-chars-forward ediff-whitespace) (while (> n 1) (funcall fwd-word-fun) @@ -1197,14 +1250,17 @@ argument to `skip-chars-forward'." (funcall fwd-word-fun)) (point)))) +(defun ediff-same-file-contents (f1 f2) + "T if F1 and F2 have identical contents." + (let ((res (call-process ediff-cmp-program nil nil nil f1 f2))) + (and (numberp res) (eq res 0)))) + ;;; 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)) +;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1) +;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body)) ;;; End: -(provide 'ediff-diff) - ;; ediff-diff.el ends here