;;; 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 <kifer@cs.sunysb.edu>
;;; 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
.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)
;;; 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
;; 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)
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))))))
(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)
(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)
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))
)))
)))
- ))) ; end ediff-eval-in-buffer
+ ))) ; end ediff-with-current-buffer
diff-list
))
(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)
;; 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)
(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))
))
(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.
;; 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)
(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)))
)
(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
(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)
(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
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))
)))
))
- ))) ; end ediff-eval-in-buffer
+ ))) ; end ediff-with-current-buffer
diff-list
))
;; 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" "*"))))
;; 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)
)))
(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
(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)
;; 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)
(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)
(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