(Version, mh-version): Add +cvs to version.
[bpt/emacs.git] / lisp / ediff-diff.el
CommitLineData
475f9031 1;;; ediff-diff.el --- diff-related utilities
b578f267 2
0d30b337 3;; Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
aaef169d 4;; 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
475f9031 5
50a07e18 6;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
475f9031
KH
7
8;; This file is part of GNU Emacs.
9
10;; GNU Emacs is free software; you can redistribute it and/or modify
11;; it under the terms of the GNU General Public License as published by
12;; the Free Software Foundation; either version 2, or (at your option)
13;; any later version.
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
b578f267 21;; along with GNU Emacs; see the file COPYING. If not, write to the
086add15
LK
22;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23;; Boston, MA 02110-1301, USA.
475f9031 24
3afbc435
PJ
25;;; Commentary:
26
b578f267 27;;; Code:
475f9031 28
ddc90f39
MK
29(provide 'ediff-diff)
30
31;; compiler pacifier
32(defvar ediff-default-variant)
50a07e18 33(defvar null-device)
1a24f45a 34(defvar longlines-mode)
ddc90f39
MK
35
36(eval-when-compile
37 (let ((load-path (cons (expand-file-name ".") load-path)))
38 (or (featurep 'ediff-init)
39 (load "ediff-init.el" nil nil 'nosuffix))
40 (or (featurep 'ediff-util)
41 (load "ediff-util.el" nil nil 'nosuffix))
42 ))
43;; end pacifier
44
b578f267 45(require 'ediff-init)
475f9031 46
ddc90f39 47(defgroup ediff-diff nil
3b9ae202 48 "Diff related utilities."
ddc90f39
MK
49 :prefix "ediff-"
50 :group 'ediff)
51
7d027816
MK
52;; these two must be here to prevent ediff-test-utility from barking
53(defcustom ediff-diff-program "diff"
54 "*Program to use for generating the differential of the two files."
55 :type 'string
56 :group 'ediff-diff)
57(defcustom ediff-diff3-program "diff3"
58 "*Program to be used for three-way comparison.
59Must produce output compatible with Unix's diff3 program."
60 :type 'string
61 :group 'ediff-diff)
62
513bea45 63
7d027816 64;; The following functions must precede all defcustom-defined variables.
4ae69eac 65
6de3983f
MK
66;; The following functions needed for setting diff/diff3 options
67;; test if diff supports the --binary option
68(defsubst ediff-test-utility (diff-util option &optional files)
15502042
EZ
69 (eq 0 (apply 'call-process
70 (append (list diff-util nil nil nil option) files))))
6de3983f
MK
71
72(defun ediff-diff-mandatory-option (diff-util)
73 (let ((file (if (boundp 'null-device) null-device "/dev/null")))
74 (cond ((not (memq system-type '(ms-dos windows-nt windows-95)))
75 "")
76 ((and (string= diff-util ediff-diff-program)
77 (ediff-test-utility
78 ediff-diff-program "--binary" (list file file)))
79 "--binary")
80 ((and (string= diff-util ediff-diff3-program)
81 (ediff-test-utility
82 ediff-diff3-program "--binary" (list file file file)))
83 "--binary")
84 (t ""))))
85
86;; make sure that mandatory options are added even if the user changes
87;; ediff-diff-options or ediff-diff3-options in the customization widget
88(defun ediff-reset-diff-options (symb val)
50a07e18
MK
89 (let* ((diff-program
90 (if (eq symb 'ediff-diff-options)
6de3983f
MK
91 ediff-diff-program
92 ediff-diff3-program))
93 (mandatory-option (ediff-diff-mandatory-option diff-program))
94 (spacer (if (string-equal mandatory-option "") "" " ")))
50a07e18 95 (set symb
6de3983f
MK
96 (if (string-match mandatory-option val)
97 val
98 (concat mandatory-option spacer val)))
99 ))
100
101
ddc90f39 102(defcustom ediff-shell
475f9031 103 (cond ((eq system-type 'emx) "cmd") ; OS/2
bbe6126c
MK
104 ((memq system-type '(ms-dos windows-nt windows-95))
105 shell-file-name) ; no standard name on MS-DOS
475f9031
KH
106 ((memq system-type '(vax-vms axp-vms)) "*dcl*") ; VMS
107 (t "sh")) ; UNIX
50a07e18
MK
108 "*The shell used to run diff and patch.
109If user's .profile or .cshrc files are set up correctly, any shell
110will do. However, some people set $prompt or other things
111incorrectly, which leads to undesirable output messages. These may
112cause Ediff to fail. In such a case, set `ediff-shell' to a shell that
113you are not using or, better, fix your shell's startup file."
ddc90f39
MK
114 :type 'string
115 :group 'ediff-diff)
475f9031 116
328b4b70
MK
117(defcustom ediff-cmp-program "cmp"
118 "*Utility to use to determine if two files are identical.
119It must return code 0, if its arguments are identical files."
120 :type 'string
121 :group 'ediff-diff)
475f9031 122
3af0304a 123(defcustom ediff-cmp-options nil
ff4968b6
RS
124 "*Options to pass to `ediff-cmp-program'.
125If GNU diff is used as `ediff-cmp-program', then the most useful options
50a07e18 126are `-I REGEXP', to ignore changes whose lines match the REGEXP."
3af0304a
MK
127 :type '(repeat string)
128 :group 'ediff-diff)
129
6de3983f 130(defcustom ediff-diff-options ""
71296446 131 "*Options to pass to `ediff-diff-program'.
50a07e18 132If Unix diff is used as `ediff-diff-program', then the most useful options are
475f9031 133`-w', to ignore space, and `-i', to ignore case of letters.
bd698e98 134At present, the option `-c' is not allowed."
6de3983f 135 :set 'ediff-reset-diff-options
ddc90f39
MK
136 :type 'string
137 :group 'ediff-diff)
475f9031 138
ddc90f39 139(defcustom ediff-custom-diff-program ediff-diff-program
475f9031 140 "*Program to use for generating custom diff output for saving it in a file.
ddc90f39
MK
141This output is not used by Ediff internally."
142 :type 'string
143 :group 'ediff-diff)
144(defcustom ediff-custom-diff-options "-c"
145 "*Options to pass to `ediff-custom-diff-program'."
146 :type 'string
147 :group 'ediff-diff)
475f9031
KH
148
149;;; Support for diff3
150
4960e757 151(defvar ediff-match-diff3-line "^====\\(.?\\)\C-m?$"
475f9031 152 "Pattern to match lines produced by diff3 that describe differences.")
50a07e18 153(defcustom ediff-diff3-options ""
ddc90f39 154 "*Options to pass to `ediff-diff3-program'."
6de3983f 155 :set 'ediff-reset-diff-options
ddc90f39
MK
156 :type 'string
157 :group 'ediff-diff)
158(defcustom ediff-diff3-ok-lines-regexp
bbe6126c 159 "^\\([1-3]:\\|====\\| \\|.*Warning *:\\|.*No newline\\|.*missing newline\\|^\C-m$\\)"
475f9031 160 "*Regexp that matches normal output lines from `ediff-diff3-program'.
ddc90f39
MK
161Lines that do not match are assumed to be error messages."
162 :type 'regexp
163 :group 'ediff-diff)
475f9031
KH
164
165;; keeps the status of the current diff in 3-way jobs.
166;; the status can be =diff(A), =diff(B), or =diff(A+B)
167(ediff-defvar-local ediff-diff-status "" "")
168
71296446 169
50a07e18 170;;; Fine differences
475f9031 171
4ae69eac 172(ediff-defvar-local ediff-auto-refine (if (ediff-has-face-support-p) 'on 'nix)
475f9031
KH
173 "If `on', Ediff auto-highlights fine diffs for the current diff region.
174If `off', auto-highlighting is not used. If `nix', no fine diffs are shown
175at all, unless the user force-refines the region by hitting `*'.
176
177This variable can be set either in .emacs or toggled interactively.
178Use `setq-default' if setting it in .emacs")
179
180(ediff-defvar-local ediff-ignore-similar-regions nil
181 "*If t, skip over difference regions that differ only in the white space and line breaks.
182This variable can be set either in .emacs or toggled interactively.
183Use `setq-default' if setting it in .emacs")
184
bbe6126c
MK
185(ediff-defvar-local ediff-auto-refine-limit 1400
186 "*Auto-refine only the regions of this size \(in bytes\) or less.")
71296446 187
475f9031
KH
188;;; General
189
50a07e18 190(defvar ediff-diff-ok-lines-regexp
c004db97
MK
191 (concat
192 "^\\("
193 "[0-9,]+[acd][0-9,]+\C-m?$"
194 "\\|[<>] "
195 "\\|---"
196 "\\|.*Warning *:"
197 "\\|.*No +newline"
198 "\\|.*missing +newline"
199 "\\|^\C-m?$"
200 "\\)")
475f9031
KH
201 "Regexp that matches normal output lines from `ediff-diff-program'.
202This is mostly lifted from Emerge, except that Ediff also considers
203warnings and `Missing newline'-type messages to be normal output.
204Lines that do not match are assumed to be error messages.")
205
c004db97
MK
206(defvar ediff-match-diff-line
207 (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
208 (concat "^" x "\\([acd]\\)" x "\C-m?$"))
475f9031
KH
209 "Pattern to match lines produced by diff that describe differences.")
210
211(ediff-defvar-local ediff-setup-diff-regions-function nil
212 "value is a function symbol depending on the kind of job is to be done.
213For 2-way jobs and for ediff-merge, it should be `ediff-setup-diff-regions'.
214For jobs requiring diff3, it should be `ediff-setup-diff-regions3'.
215
216The function should take three mandatory arguments, file-A, file-B, and
217file-C. It may ignore file C for diff2 jobs. It should also take
218one optional arguments, diff-number to refine.")
219
71296446 220
475f9031
KH
221;;; Functions
222
223;; Generate the difference vector and overlays for the two files
224;; With optional arg REG-TO-REFINE, refine this region.
225;; File-C argument is not used here. It is there just because
226;; ediff-setup-diff-regions is called via a funcall to
227;; ediff-setup-diff-regions-function, which can also have the value
228;; ediff-setup-diff-regions3, which takes 4 arguments.
229(defun ediff-setup-diff-regions (file-A file-B file-C)
6dfd1bcc
MK
230 ;; looking either for '-c' or a 'c' in a set of clustered non-long options
231 (if (string-match "^-c\\| -c\\|-[^- ]+c" ediff-diff-options)
bd698e98 232 (error "Option `-c' is not allowed in `ediff-diff-options'"))
71296446 233
bbe6126c 234 ;; create, if it doesn't exist
475f9031
KH
235 (or (ediff-buffer-live-p ediff-diff-buffer)
236 (setq ediff-diff-buffer
237 (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*"))))
bbe6126c 238 (ediff-make-diff2-buffer ediff-diff-buffer file-A file-B)
475f9031 239 (ediff-prepare-error-list ediff-diff-ok-lines-regexp ediff-diff-buffer)
475f9031
KH
240 (ediff-convert-diffs-to-overlays
241 (ediff-extract-diffs
4ae69eac 242 ediff-diff-buffer ediff-word-mode ediff-narrow-bounds)))
bbe6126c 243
52fa07ba
MK
244;; Run the diff program on FILE1 and FILE2 and put the output in DIFF-BUFFER
245;; Return the size of DIFF-BUFFER
513bea45 246;; The return code isn't used in the program at present.
bbe6126c 247(defun ediff-make-diff2-buffer (diff-buffer file1 file2)
92c51e07
MK
248 (let ((file1-size (ediff-file-size file1))
249 (file2-size (ediff-file-size file2)))
250 (cond ((not (numberp file1-size))
251 (message "Can't find file: %s"
252 (ediff-abbreviate-file-name file1))
253 (sit-for 2)
254 ;; 1 is an error exit code
255 1)
256 ((not (numberp file2-size))
257 (message "Can't find file: %s"
258 (ediff-abbreviate-file-name file2))
259 (sit-for 2)
260 ;; 1 is an error exit code
261 1)
92c51e07
MK
262 (t (message "Computing differences between %s and %s ..."
263 (file-name-nondirectory file1)
264 (file-name-nondirectory file2))
265 ;; this erases the diff buffer automatically
266 (ediff-exec-process ediff-diff-program
267 diff-buffer
268 'synchronize
269 ediff-diff-options file1 file2)
92c51e07 270 (message "")
e756eb9f 271 (ediff-with-current-buffer diff-buffer
92c51e07 272 (buffer-size))))))
bbe6126c 273
71296446
JB
274
275
475f9031
KH
276;; If file-A/B/C is nil, do 2-way comparison with the non-nil buffers
277;; This function works for diff3 and diff2 jobs
278(defun ediff-setup-fine-diff-regions (file-A file-B file-C reg-num)
279 (or (ediff-buffer-live-p ediff-fine-diff-buffer)
280 (setq ediff-fine-diff-buffer
281 (get-buffer-create
282 (ediff-unique-buffer-name "*ediff-fine-diff" "*"))))
71296446 283
ab8a391e 284 (let (diff3-job diff-program diff-options ok-regexp diff-list)
475f9031
KH
285 (setq diff3-job ediff-3way-job
286 diff-program (if diff3-job ediff-diff3-program ediff-diff-program)
ab8a391e 287 diff-options (if diff3-job ediff-diff3-options ediff-diff-options)
475f9031
KH
288 ok-regexp (if diff3-job
289 ediff-diff3-ok-lines-regexp
290 ediff-diff-ok-lines-regexp))
71296446 291
4ad42cb5
MK
292 (ediff-message-if-verbose "Refining difference region %d ..." (1+ reg-num))
293 (ediff-exec-process diff-program ediff-fine-diff-buffer 'synchronize
ab8a391e 294 diff-options
4ad42cb5
MK
295 ;; The shuffle below is because we can compare 3-way
296 ;; or in several 2-way fashions, like fA fC, fA fB,
297 ;; or fB fC.
298 (if file-A file-A file-B)
299 (if file-B file-B file-A)
300 (if diff3-job
301 (if file-C file-C file-B))
302 ) ; exec process
71296446 303
475f9031 304 (ediff-prepare-error-list ok-regexp ediff-fine-diff-buffer)
4ae69eac
MK
305 (ediff-message-if-verbose
306 "")
4ad42cb5 307 ;; "Refining difference region %d ... done" (1+ reg-num))
71296446 308
475f9031
KH
309 (setq diff-list
310 (if diff3-job
311 (ediff-extract-diffs3
312 ediff-fine-diff-buffer '3way-comparison 'word-mode)
313 (ediff-extract-diffs ediff-fine-diff-buffer 'word-mode)))
314 ;; fixup diff-list
315 (if diff3-job
316 (cond ((not file-A)
3af0304a
MK
317 (mapcar (lambda (elt)
318 (aset elt 0 nil)
319 (aset elt 1 nil))
475f9031
KH
320 (cdr diff-list)))
321 ((not file-B)
3af0304a
MK
322 (mapcar (lambda (elt)
323 (aset elt 2 nil)
324 (aset elt 3 nil))
475f9031
KH
325 (cdr diff-list)))
326 ((not file-C)
3af0304a
MK
327 (mapcar (lambda (elt)
328 (aset elt 4 nil)
329 (aset elt 5 nil))
475f9031
KH
330 (cdr diff-list)))
331 ))
71296446 332
475f9031
KH
333 (ediff-convert-fine-diffs-to-overlays diff-list reg-num)
334 ))
71296446
JB
335
336
475f9031 337(defun ediff-prepare-error-list (ok-regexp diff-buff)
4ad42cb5
MK
338 (or (ediff-buffer-live-p ediff-error-buffer)
339 (setq ediff-error-buffer
340 (get-buffer-create (ediff-unique-buffer-name
341 "*ediff-errors" "*"))))
e756eb9f 342 (ediff-with-current-buffer ediff-error-buffer
4ad42cb5 343 (erase-buffer)
e756eb9f 344 (insert (ediff-with-current-buffer diff-buff (buffer-string)))
4ad42cb5
MK
345 (goto-char (point-min))
346 (delete-matching-lines ok-regexp)
347 (if (memq system-type '(vax-vms axp-vms))
348 (delete-matching-lines "^$")))
349 ;; If diff reports errors, show them then quit.
e756eb9f 350 (if (/= 0 (ediff-with-current-buffer ediff-error-buffer (buffer-size)))
4ad42cb5
MK
351 (let ((ctl-buf ediff-control-buffer)
352 (error-buf ediff-error-buffer))
353 (ediff-skip-unsuitable-frames)
354 (switch-to-buffer error-buf)
355 (ediff-kill-buffer-carefully ctl-buf)
50a07e18 356 (error "Errors in diff output. Diff output is in %S" diff-buff))))
475f9031
KH
357
358;; BOUNDS specifies visibility bounds to use.
359;; WORD-MODE tells whether we are in the word-mode or not.
360;; If WORD-MODE, also construct vector of diffs using word numbers.
361;; Else, use point values.
362;; This function handles diff-2 jobs including the case of
363;; merging buffers and files without ancestor.
364(defun ediff-extract-diffs (diff-buffer word-mode &optional bounds)
365 (let ((A-buffer ediff-buffer-A)
366 (B-buffer ediff-buffer-B)
367 (C-buffer ediff-buffer-C)
368 (a-prev 1) ; this is needed to set the first diff line correctly
369 (b-prev 1)
370 (c-prev 1)
371 diff-list shift-A shift-B
372 )
71296446 373
475f9031
KH
374 ;; diff list contains word numbers, unless changed later
375 (setq diff-list (cons (if word-mode 'words 'points)
376 diff-list))
377 ;; we don't use visibility bounds for buffer C when merging
378 (if bounds
379 (setq shift-A
380 (ediff-overlay-start
381 (ediff-get-value-according-to-buffer-type 'A bounds))
50a07e18 382 shift-B
475f9031
KH
383 (ediff-overlay-start
384 (ediff-get-value-according-to-buffer-type 'B bounds))))
71296446 385
475f9031 386 ;; reset point in buffers A/B/C
e756eb9f 387 (ediff-with-current-buffer A-buffer
475f9031 388 (goto-char (if shift-A shift-A (point-min))))
e756eb9f 389 (ediff-with-current-buffer B-buffer
475f9031
KH
390 (goto-char (if shift-B shift-B (point-min))))
391 (if (ediff-buffer-live-p C-buffer)
e756eb9f 392 (ediff-with-current-buffer C-buffer
475f9031 393 (goto-char (point-min))))
71296446 394
e756eb9f 395 (ediff-with-current-buffer diff-buffer
475f9031
KH
396 (goto-char (point-min))
397 (while (re-search-forward ediff-match-diff-line nil t)
027a4b6b
JB
398 (let* ((a-begin (string-to-number (buffer-substring (match-beginning 1)
399 (match-end 1))))
475f9031
KH
400 (a-end (let ((b (match-beginning 3))
401 (e (match-end 3)))
402 (if b
027a4b6b 403 (string-to-number (buffer-substring b e))
475f9031
KH
404 a-begin)))
405 (diff-type (buffer-substring (match-beginning 4) (match-end 4)))
027a4b6b
JB
406 (b-begin (string-to-number (buffer-substring (match-beginning 5)
407 (match-end 5))))
475f9031
KH
408 (b-end (let ((b (match-beginning 7))
409 (e (match-end 7)))
410 (if b
027a4b6b 411 (string-to-number (buffer-substring b e))
475f9031
KH
412 b-begin)))
413 a-begin-pt a-end-pt b-begin-pt b-end-pt
414 c-begin c-end c-begin-pt c-end-pt)
415 ;; fix the beginning and end numbers, because diff is somewhat
416 ;; strange about how it numbers lines
417 (if (string-equal diff-type "a")
418 (setq b-end (1+ b-end)
419 a-begin (1+ a-begin)
420 a-end a-begin)
421 (if (string-equal diff-type "d")
422 (setq a-end (1+ a-end)
423 b-begin (1+ b-begin)
424 b-end b-begin)
425 ;; (string-equal diff-type "c")
426 (setq a-end (1+ a-end)
427 b-end (1+ b-end))))
71296446 428
475f9031
KH
429 (if (eq ediff-default-variant 'default-B)
430 (setq c-begin b-begin
431 c-end b-end)
432 (setq c-begin a-begin
433 c-end a-end))
71296446 434
475f9031
KH
435 ;; compute main diff vector
436 (if word-mode
437 ;; make diff-list contain word numbers
50a07e18 438 (setq diff-list
475f9031
KH
439 (nconc diff-list
440 (list
441 (if (ediff-buffer-live-p C-buffer)
442 (vector (- a-begin a-prev) (- a-end a-begin)
443 (- b-begin b-prev) (- b-end b-begin)
444 (- c-begin c-prev) (- c-end c-begin)
4ad42cb5
MK
445 nil nil ; dummy ancestor
446 nil ; state of diff
447 nil ; state of merge
448 nil ; state of ancestor
475f9031
KH
449 )
450 (vector (- a-begin a-prev) (- a-end a-begin)
451 (- b-begin b-prev) (- b-end b-begin)
452 nil nil ; dummy buf C
4ad42cb5 453 nil nil ; dummy ancestor
475f9031
KH
454 nil ; state of diff
455 nil ; state of merge
4ad42cb5 456 nil ; state of ancestor
475f9031
KH
457 ))
458 ))
459 a-prev a-end
460 b-prev b-end
461 c-prev c-end)
462 ;; else convert lines to points
e756eb9f 463 (ediff-with-current-buffer A-buffer
8ea74b0e
MK
464 (let ((longlines-mode-val
465 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
466 ;; we must disable and then restore longlines-mode
467 (if (eq longlines-mode-val 1)
468 (longlines-mode 0))
469 (forward-line (- a-begin a-prev))
470 (setq a-begin-pt (point))
471 (forward-line (- a-end a-begin))
472 (setq a-end-pt (point)
473 a-prev a-end)
474 (if (eq longlines-mode-val 1)
475 (longlines-mode longlines-mode-val))
476 ))
e756eb9f 477 (ediff-with-current-buffer B-buffer
8ea74b0e
MK
478 (let ((longlines-mode-val
479 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
480 (if (eq longlines-mode-val 1)
481 (longlines-mode 0))
482 (forward-line (- b-begin b-prev))
483 (setq b-begin-pt (point))
484 (forward-line (- b-end b-begin))
485 (setq b-end-pt (point)
486 b-prev b-end)
487 (if (eq longlines-mode-val 1)
488 (longlines-mode longlines-mode-val))
489 ))
475f9031 490 (if (ediff-buffer-live-p C-buffer)
e756eb9f 491 (ediff-with-current-buffer C-buffer
8ea74b0e
MK
492 (let ((longlines-mode-val
493 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
494 (if (eq longlines-mode-val 1)
495 (longlines-mode 0))
496 (forward-line (- c-begin c-prev))
497 (setq c-begin-pt (point))
498 (forward-line (- c-end c-begin))
499 (setq c-end-pt (point)
500 c-prev c-end)
501 (if (eq longlines-mode-val 1)
502 (longlines-mode longlines-mode-val))
503 )))
50a07e18 504 (setq diff-list
475f9031
KH
505 (nconc
506 diff-list
507 (list
508 (if (ediff-buffer-live-p C-buffer)
509 (vector
510 a-begin-pt a-end-pt b-begin-pt b-end-pt
511 c-begin-pt c-end-pt
4ad42cb5 512 nil nil ; dummy ancestor
475f9031
KH
513 ;; state of diff
514 ;; shows which buff is different from the other two
515 (if (eq ediff-default-variant 'default-B) 'A 'B)
4ad42cb5
MK
516 ediff-default-variant ; state of merge
517 nil ; state of ancestor
475f9031 518 )
4ad42cb5
MK
519 (vector a-begin-pt a-end-pt
520 b-begin-pt b-end-pt
521 nil nil ; dummy buf C
522 nil nil ; dummy ancestor
523 nil nil ; dummy state of diff & merge
524 nil ; dummy state of ancestor
50a07e18 525 )))
475f9031 526 )))
71296446 527
e756eb9f 528 ))) ; end ediff-with-current-buffer
475f9031
KH
529 diff-list
530 ))
71296446 531
475f9031 532
4ad42cb5
MK
533(defun ediff-convert-diffs-to-overlays (diff-list)
534 (ediff-set-diff-overlays-in-one-buffer 'A diff-list)
535 (ediff-set-diff-overlays-in-one-buffer 'B diff-list)
536 (if ediff-3way-job
537 (ediff-set-diff-overlays-in-one-buffer 'C diff-list))
538 (if ediff-merge-with-ancestor-job
539 (ediff-set-diff-overlays-in-one-buffer 'Ancestor diff-list))
540 ;; set up vector showing the status of merge regions
541 (if ediff-merge-job
542 (setq ediff-state-of-merge
543 (vconcat
3af0304a
MK
544 (mapcar (lambda (elt)
545 (let ((state-of-merge (aref elt 9))
546 (state-of-ancestor (aref elt 10)))
547 (vector
548 ;; state of merge: prefers/default-A/B or combined
549 (if state-of-merge (format "%S" state-of-merge))
550 ;; whether the ancestor region is empty
551 state-of-ancestor)))
4ad42cb5
MK
552 ;; the first elt designates type of list
553 (cdr diff-list))
554 )))
555 (message "Processing difference regions ... done"))
556
71296446 557
475f9031
KH
558(defun ediff-set-diff-overlays-in-one-buffer (buf-type diff-list)
559 (let* ((current-diff -1)
560 (buff (ediff-get-buffer buf-type))
17561e4f 561 (ctl-buf ediff-control-buffer)
475f9031
KH
562 ;; ediff-extract-diffs puts the type of diff-list as the first elt
563 ;; of this list. The type is either 'points or 'words
564 (diff-list-type (car diff-list))
565 (shift (ediff-overlay-start
566 (ediff-get-value-according-to-buffer-type
567 buf-type ediff-narrow-bounds)))
568 (limit (ediff-overlay-end
50a07e18 569 (ediff-get-value-according-to-buffer-type
475f9031
KH
570 buf-type ediff-narrow-bounds)))
571 diff-overlay-list list-element total-diffs
4ad42cb5 572 begin end pt-saved overlay state-of-diff)
475f9031
KH
573
574 (setq diff-list (cdr diff-list)) ; discard diff list type
575 (setq total-diffs (length diff-list))
71296446 576
475f9031 577 ;; shift, if necessary
e756eb9f 578 (ediff-with-current-buffer buff (setq pt-saved shift))
71296446 579
475f9031
KH
580 (while diff-list
581 (setq current-diff (1+ current-diff)
582 list-element (car diff-list)
583 begin (aref list-element (cond ((eq buf-type 'A) 0)
584 ((eq buf-type 'B) 2)
4ad42cb5
MK
585 ((eq buf-type 'C) 4)
586 (t 6))) ; Ancestor
475f9031
KH
587 end (aref list-element (cond ((eq buf-type 'A) 1)
588 ((eq buf-type 'B) 3)
4ad42cb5
MK
589 ((eq buf-type 'C) 5)
590 (t 7))) ; Ancestor
591 state-of-diff (aref list-element 8)
592 )
71296446 593
475f9031 594 (cond ((and (not (eq buf-type state-of-diff))
4ad42cb5 595 (not (eq buf-type 'Ancestor))
475f9031
KH
596 (memq state-of-diff '(A B C)))
597 (setq state-of-diff
598 (car (delq buf-type (delq state-of-diff (list 'A 'B 'C)))))
599 (setq state-of-diff (format "=diff(%S)" state-of-diff))
475f9031 600 )
4ad42cb5 601 (t (setq state-of-diff nil)))
71296446 602
475f9031
KH
603 ;; Put overlays at appropriate places in buffer
604 ;; convert word numbers to points, if necessary
605 (if (eq diff-list-type 'words)
606 (progn
e756eb9f 607 (ediff-with-current-buffer buff (goto-char pt-saved))
17561e4f
MK
608 (ediff-with-current-buffer ctl-buf
609 (setq begin (ediff-goto-word (1+ begin) buff)
610 end (ediff-goto-word end buff 'end)))
475f9031
KH
611 (if (> end limit) (setq end limit))
612 (if (> begin end) (setq begin end))
e756eb9f 613 (setq pt-saved (ediff-with-current-buffer buff (point)))))
475f9031 614 (setq overlay (ediff-make-bullet-proof-overlay begin end buff))
71296446 615
475f9031
KH
616 (ediff-overlay-put overlay 'priority ediff-shadow-overlay-priority)
617 (ediff-overlay-put overlay 'ediff-diff-num current-diff)
4ae69eac 618 (if (and (ediff-has-face-support-p)
4ad42cb5
MK
619 ediff-use-faces ediff-highlight-all-diffs)
620 (ediff-set-overlay-face
621 overlay (ediff-background-face buf-type current-diff)))
475f9031
KH
622
623 (if (= 0 (mod current-diff 10))
624 (message "Buffer %S: Processing difference region %d of %d"
625 buf-type current-diff total-diffs))
3af0304a
MK
626 ;; Record all overlays for this difference.
627 ;; The 2-d elt, nil, is a place holder for the fine diff vector.
628 ;; The 3-d elt, nil, is a place holder for no-fine-diffs flag.
629 ;; The 4-th elt says which diff region is different from the other two
630 ;; (3-way jobs only).
475f9031
KH
631 (setq diff-overlay-list
632 (nconc
633 diff-overlay-list
4ad42cb5 634 (list (vector overlay nil nil state-of-diff)))
475f9031
KH
635 diff-list
636 (cdr diff-list))
637 ) ; while
71296446 638
e756eb9f 639 (set (ediff-get-symbol-from-alist buf-type ediff-difference-vector-alist)
4ad42cb5 640 (vconcat diff-overlay-list))
475f9031 641 ))
4ad42cb5 642
475f9031
KH
643;; `n' is the diff region to work on. Default is ediff-current-difference.
644;; if `flag' is 'noforce then make fine-diffs only if this region's fine
645;; diffs have not been computed before.
646;; if `flag' is 'skip then don't compute fine diffs for this region.
50a07e18 647(defun ediff-make-fine-diffs (&optional n flag)
475f9031 648 (or n (setq n ediff-current-difference))
71296446 649
475f9031 650 (if (< ediff-number-of-differences 1)
bbe6126c 651 (error ediff-NO-DIFFERENCES))
71296446 652
475f9031
KH
653 (if ediff-word-mode
654 (setq flag 'skip
655 ediff-auto-refine 'nix))
71296446 656
475f9031
KH
657 (or (< n 0)
658 (>= n ediff-number-of-differences)
659 ;; n is within the range
660 (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
661 (file-A ediff-temp-file-A)
662 (file-B ediff-temp-file-B)
663 (file-C ediff-temp-file-C)
664 (empty-A (ediff-empty-diff-region-p n 'A))
665 (empty-B (ediff-empty-diff-region-p n 'B))
666 (empty-C (ediff-empty-diff-region-p n 'C))
667 (whitespace-A (ediff-whitespace-diff-region-p n 'A))
668 (whitespace-B (ediff-whitespace-diff-region-p n 'B))
669 (whitespace-C (ediff-whitespace-diff-region-p n 'C))
670 cumulative-fine-diff-length)
71296446 671
ddc90f39 672 (cond ;; If one of the regions is empty (or 2 in 3way comparison)
4ad42cb5
MK
673 ;; then don't refine.
674 ;; If the region happens to be entirely whitespace or empty then
675 ;; mark as such.
475f9031
KH
676 ((> (length (delq nil (list empty-A empty-B empty-C))) 1)
677 (if (and (ediff-looks-like-combined-merge n)
678 ediff-merge-job)
679 (ediff-set-fine-overlays-in-one-buffer 'C nil n))
4ad42cb5
MK
680 (if ediff-3way-comparison-job
681 (ediff-message-if-verbose
682 "Region %d is empty in all buffers but %S"
50a07e18 683 (1+ n)
4ad42cb5
MK
684 (cond ((not empty-A) 'A)
685 ((not empty-B) 'B)
686 ((not empty-C) 'C)))
687 (ediff-message-if-verbose
688 "Region %d in buffer %S is empty"
50a07e18 689 (1+ n)
4ad42cb5
MK
690 (cond (empty-A 'A)
691 (empty-B 'B)
692 (empty-C 'C)))
693 )
bbe6126c 694 ;; if all regions happen to be whitespace
4ad42cb5 695 (if (and whitespace-A whitespace-B whitespace-C)
bbe6126c 696 ;; mark as space only
475f9031 697 (ediff-mark-diff-as-space-only n t)
bbe6126c
MK
698 ;; if some regions are white and others don't, then mark as
699 ;; non-white-space-only
475f9031 700 (ediff-mark-diff-as-space-only n nil)))
ddc90f39
MK
701
702 ;; don't compute fine diffs if diff vector exists
703 ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n 'A))
704 (if (ediff-no-fine-diffs-p n)
705 (message
706 "Only white-space differences in region %d %s"
707 (1+ n)
708 (cond ((eq (ediff-no-fine-diffs-p n) 'A)
709 "in buffers B & C")
710 ((eq (ediff-no-fine-diffs-p n) 'B)
711 "in buffers A & C")
712 ((eq (ediff-no-fine-diffs-p n) 'C)
713 "in buffers A & B")
714 (t "")))))
475f9031
KH
715 ;; don't compute fine diffs for this region
716 ((eq flag 'skip)
717 (or (ediff-get-fine-diff-vector n 'A)
718 (memq ediff-auto-refine '(off nix))
4ad42cb5 719 (ediff-message-if-verbose
3af0304a 720 "Region %d exceeds the auto-refinement limit. Type `%s' to refine"
475f9031 721 (1+ n)
4ad42cb5
MK
722 (substitute-command-keys
723 "\\[ediff-make-or-kill-fine-diffs]")
475f9031
KH
724 )))
725 (t
475f9031
KH
726 ;; recompute fine diffs
727 (ediff-wordify
728 (ediff-get-diff-posn 'A 'beg n)
729 (ediff-get-diff-posn 'A 'end n)
730 ediff-buffer-A
731 tmp-buffer
732 ediff-control-buffer)
4ad42cb5
MK
733 (setq file-A
734 (ediff-make-temp-file tmp-buffer "fineDiffA" file-A))
71296446 735
475f9031
KH
736 (ediff-wordify
737 (ediff-get-diff-posn 'B 'beg n)
738 (ediff-get-diff-posn 'B 'end n)
739 ediff-buffer-B
740 tmp-buffer
741 ediff-control-buffer)
4ad42cb5
MK
742 (setq file-B
743 (ediff-make-temp-file tmp-buffer "fineDiffB" file-B))
71296446 744
475f9031
KH
745 (if ediff-3way-job
746 (progn
747 (ediff-wordify
748 (ediff-get-diff-posn 'C 'beg n)
749 (ediff-get-diff-posn 'C 'end n)
750 ediff-buffer-C
751 tmp-buffer
752 ediff-control-buffer)
4ad42cb5
MK
753 (setq file-C
754 (ediff-make-temp-file
755 tmp-buffer "fineDiffC" file-C))))
71296446 756
475f9031
KH
757 ;; save temp file names.
758 (setq ediff-temp-file-A file-A
759 ediff-temp-file-B file-B
760 ediff-temp-file-C file-C)
71296446 761
475f9031
KH
762 ;; set the new vector of fine diffs, if none exists
763 (cond ((and ediff-3way-job whitespace-A)
764 (ediff-setup-fine-diff-regions nil file-B file-C n))
765 ((and ediff-3way-job whitespace-B)
766 (ediff-setup-fine-diff-regions file-A nil file-C n))
767 ((and ediff-3way-job
bbe6126c
MK
768 ;; In merge-jobs, whitespace-C is t, since
769 ;; ediff-empty-diff-region-p returns t in this case
770 whitespace-C)
475f9031
KH
771 (ediff-setup-fine-diff-regions file-A file-B nil n))
772 (t
773 (ediff-setup-fine-diff-regions file-A file-B file-C n)))
71296446 774
475f9031
KH
775 (setq cumulative-fine-diff-length
776 (+ (length (ediff-get-fine-diff-vector n 'A))
bbe6126c
MK
777 (length (ediff-get-fine-diff-vector n 'B))
778 ;; in merge jobs, the merge buffer is never refined
779 (if (and file-C (not ediff-merge-job))
780 (length (ediff-get-fine-diff-vector n 'C))
781 0)))
71296446 782
475f9031
KH
783 (cond ((or
784 ;; all regions are white space
785 (and whitespace-A whitespace-B whitespace-C)
786 ;; none is white space and no fine diffs detected
787 (and (not whitespace-A)
788 (not whitespace-B)
789 (not (and ediff-3way-job whitespace-C))
790 (eq cumulative-fine-diff-length 0)))
791 (ediff-mark-diff-as-space-only n t)
4ad42cb5 792 (ediff-message-if-verbose
475f9031
KH
793 "Only white-space differences in region %d" (1+ n)))
794 ((eq cumulative-fine-diff-length 0)
4ad42cb5 795 (ediff-message-if-verbose
475f9031
KH
796 "Only white-space differences in region %d %s"
797 (1+ n)
ddc90f39
MK
798 (cond (whitespace-A (ediff-mark-diff-as-space-only n 'A)
799 "in buffers B & C")
800 (whitespace-B (ediff-mark-diff-as-space-only n 'B)
801 "in buffers A & C")
802 (whitespace-C (ediff-mark-diff-as-space-only n 'C)
803 "in buffers A & B"))))
50a07e18 804 (t
475f9031
KH
805 (ediff-mark-diff-as-space-only n nil)))
806 )
807 ) ; end cond
808 (ediff-set-fine-diff-properties n)
809 )))
71296446 810
475f9031
KH
811;; Interface to ediff-make-fine-diffs. Checks for auto-refine limit, etc.
812(defun ediff-install-fine-diff-if-necessary (n)
743a79af
MK
813 (cond ((and (eq ediff-auto-refine 'on)
814 ediff-use-faces
815 (not (eq ediff-highlighting-style 'off))
816 (not (eq ediff-highlighting-style 'ascii)))
475f9031
KH
817 (if (and
818 (> ediff-auto-refine-limit
819 (- (ediff-get-diff-posn 'A 'end n)
820 (ediff-get-diff-posn 'A 'beg n)))
821 (> ediff-auto-refine-limit
822 (- (ediff-get-diff-posn 'B 'end n)
823 (ediff-get-diff-posn 'B 'beg n))))
824 (ediff-make-fine-diffs n 'noforce)
825 (ediff-make-fine-diffs n 'skip)))
71296446 826
475f9031
KH
827 ;; highlight iff fine diffs already exist
828 ((eq ediff-auto-refine 'off)
829 (ediff-make-fine-diffs n 'skip))))
71296446
JB
830
831
475f9031
KH
832;; if fine diff vector is not set for diff N, then do nothing
833(defun ediff-set-fine-diff-properties (n &optional default)
4ae69eac 834 (or (not (ediff-has-face-support-p))
475f9031
KH
835 (< n 0)
836 (>= n ediff-number-of-differences)
4ae69eac 837 ;; when faces are supported, set faces and priorities of fine overlays
475f9031
KH
838 (progn
839 (ediff-set-fine-diff-properties-in-one-buffer 'A n default)
840 (ediff-set-fine-diff-properties-in-one-buffer 'B n default)
841 (if ediff-3way-job
842 (ediff-set-fine-diff-properties-in-one-buffer 'C n default)))))
71296446 843
475f9031
KH
844(defun ediff-set-fine-diff-properties-in-one-buffer (buf-type
845 n &optional default)
846 (let ((fine-diff-vector (ediff-get-fine-diff-vector n buf-type))
50a07e18 847 (face (if default
475f9031
KH
848 'default
849 (face-name
e756eb9f
MK
850 (ediff-get-symbol-from-alist
851 buf-type ediff-fine-diff-face-alist))))
475f9031
KH
852 (priority (if default
853 0
854 (1+ (or (ediff-overlay-get
855 (symbol-value
e756eb9f
MK
856 (ediff-get-symbol-from-alist
857 buf-type
858 ediff-current-diff-overlay-alist))
475f9031
KH
859 'priority)
860 0)))))
3af0304a
MK
861 (mapcar (lambda (overl)
862 (ediff-set-overlay-face overl face)
863 (ediff-overlay-put overl 'priority priority))
864 fine-diff-vector)))
71296446 865
086171bf 866;; Set overlays over the regions that denote delimiters
475f9031 867(defun ediff-set-fine-overlays-for-combined-merge (diff-list reg-num)
086171bf
MK
868 (let (overlay overlay-list)
869 (while diff-list
870 (condition-case nil
871 (setq overlay
872 (ediff-make-bullet-proof-overlay
873 (nth 0 diff-list) (nth 1 diff-list) ediff-buffer-C))
874 (error ""))
875 (setq overlay-list (cons overlay overlay-list))
876 (if (> (length diff-list) 1)
877 (setq diff-list (cdr (cdr diff-list)))
878 (error "ediff-set-fine-overlays-for-combined-merge: corrupt list of
879delimiter regions"))
880 )
881 (setq overlay-list (reverse overlay-list))
882 (ediff-set-fine-diff-vector
883 reg-num 'C (apply 'vector overlay-list))
475f9031 884 ))
71296446
JB
885
886
475f9031
KH
887;; Convert diff list to overlays for a given DIFF-REGION
888;; in buffer of type BUF-TYPE
889(defun ediff-set-fine-overlays-in-one-buffer (buf-type diff-list region-num)
890 (let* ((current-diff -1)
891 (reg-start (ediff-get-diff-posn buf-type 'beg region-num))
892 (buff (ediff-get-buffer buf-type))
17561e4f 893 (ctl-buf ediff-control-buffer)
475f9031
KH
894 combined-merge-diff-list
895 diff-overlay-list list-element
896 begin end overlay)
897
898 (ediff-clear-fine-differences-in-one-buffer region-num buf-type)
899 (setq diff-list (cdr diff-list)) ; discard list type (words or points)
e756eb9f 900 (ediff-with-current-buffer buff (goto-char reg-start))
71296446 901
475f9031
KH
902 ;; if it is a combined merge then set overlays in buff C specially
903 (if (and ediff-merge-job (eq buf-type 'C)
904 (setq combined-merge-diff-list
905 (ediff-looks-like-combined-merge region-num)))
906 (ediff-set-fine-overlays-for-combined-merge
907 combined-merge-diff-list region-num)
908 ;; regular fine diff
909 (while diff-list
910 (setq current-diff (1+ current-diff)
911 list-element (car diff-list)
912 begin (aref list-element (cond ((eq buf-type 'A) 0)
913 ((eq buf-type 'B) 2)
914 (t 4))) ; buf C
915 end (aref list-element (cond ((eq buf-type 'A) 1)
916 ((eq buf-type 'B) 3)
917 (t 5)))) ; buf C
918 (if (not (or begin end))
919 () ; skip this diff
920 ;; Put overlays at appropriate places in buffers
921 ;; convert lines to points, if necessary
17561e4f
MK
922 (ediff-with-current-buffer ctl-buf
923 (setq begin (ediff-goto-word (1+ begin) buff)
924 end (ediff-goto-word end buff 'end)))
475f9031
KH
925 (setq overlay (ediff-make-bullet-proof-overlay begin end buff))
926 ;; record all overlays for this difference region
927 (setq diff-overlay-list (nconc diff-overlay-list (list overlay))))
71296446 928
475f9031
KH
929 (setq diff-list (cdr diff-list))
930 ) ; while
931 ;; convert the list of difference information into a vector
932 ;; for fast access
50a07e18 933 (ediff-set-fine-diff-vector
4ad42cb5 934 region-num buf-type (vconcat diff-overlay-list))
475f9031
KH
935 )))
936
937
50a07e18
MK
938(defsubst ediff-convert-fine-diffs-to-overlays (diff-list region-num)
939 (ediff-set-fine-overlays-in-one-buffer 'A diff-list region-num)
940 (ediff-set-fine-overlays-in-one-buffer 'B diff-list region-num)
941 (if ediff-3way-job
942 (ediff-set-fine-overlays-in-one-buffer 'C diff-list region-num)
943 ))
944
945
475f9031
KH
946;; Stolen from emerge.el
947(defun ediff-get-diff3-group (file)
948 ;; This save-excursion allows ediff-get-diff3-group to be called for the
949 ;; various groups of lines (1, 2, 3) in any order, and for the lines to
950 ;; appear in any order. The reason this is necessary is that Gnu diff3
951 ;; can produce the groups in the order 1, 2, 3 or 1, 3, 2.
952 (save-excursion
953 (re-search-forward
4960e757 954 (concat "^" file ":\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\\([ac]\\)\C-m?$"))
475f9031
KH
955 (beginning-of-line 2)
956 ;; treatment depends on whether it is an "a" group or a "c" group
957 (if (string-equal (buffer-substring (match-beginning 4) (match-end 4)) "c")
958 ;; it is a "c" group
959 (if (match-beginning 2)
960 ;; it has two numbers
027a4b6b 961 (list (string-to-number
475f9031 962 (buffer-substring (match-beginning 1) (match-end 1)))
027a4b6b 963 (1+ (string-to-number
475f9031
KH
964 (buffer-substring (match-beginning 3) (match-end 3)))))
965 ;; it has one number
027a4b6b 966 (let ((x (string-to-number
475f9031
KH
967 (buffer-substring (match-beginning 1) (match-end 1)))))
968 (list x (1+ x))))
969 ;; it is an "a" group
027a4b6b 970 (let ((x (1+ (string-to-number
475f9031
KH
971 (buffer-substring (match-beginning 1) (match-end 1))))))
972 (list x x)))))
973
974
975;; If WORD-MODE, construct vector of diffs using word numbers.
976;; Else, use point values.
977;; WORD-MODE also tells if we are in the word-mode or not.
978;; If THREE-WAY-COMP, then it is a 3-way comparison. Else, it is merging
4ad42cb5
MK
979;; with ancestor, in which case buffer-C contents is identical to buffer-A/B,
980;; contents (unless buffer-A is narrowed) depending on ediff-default-variant's
981;; value.
475f9031
KH
982;; BOUNDS specifies visibility bounds to use.
983(defun ediff-extract-diffs3 (diff-buffer word-mode three-way-comp
984 &optional bounds)
985 (let ((A-buffer ediff-buffer-A)
986 (B-buffer ediff-buffer-B)
987 (C-buffer ediff-buffer-C)
4ad42cb5 988 (anc-buffer ediff-ancestor-buffer)
475f9031
KH
989 (a-prev 1) ; needed to set the first diff line correctly
990 (b-prev 1)
991 (c-prev 1)
4ad42cb5 992 (anc-prev 1)
475f9031
KH
993 diff-list shift-A shift-B shift-C
994 )
71296446 995
475f9031
KH
996 ;; diff list contains word numbers or points, depending on word-mode
997 (setq diff-list (cons (if word-mode 'words 'points)
998 diff-list))
999 (if bounds
1000 (setq shift-A
1001 (ediff-overlay-start
1002 (ediff-get-value-according-to-buffer-type 'A bounds))
50a07e18 1003 shift-B
475f9031
KH
1004 (ediff-overlay-start
1005 (ediff-get-value-according-to-buffer-type 'B bounds))
50a07e18 1006 shift-C
475f9031
KH
1007 (if three-way-comp
1008 (ediff-overlay-start
1009 (ediff-get-value-according-to-buffer-type 'C bounds)))))
71296446 1010
475f9031 1011 ;; reset point in buffers A, B, C
e756eb9f 1012 (ediff-with-current-buffer A-buffer
475f9031 1013 (goto-char (if shift-A shift-A (point-min))))
e756eb9f 1014 (ediff-with-current-buffer B-buffer
475f9031 1015 (goto-char (if shift-B shift-B (point-min))))
4ad42cb5 1016 (if three-way-comp
e756eb9f 1017 (ediff-with-current-buffer C-buffer
4ad42cb5
MK
1018 (goto-char (if shift-C shift-C (point-min)))))
1019 (if (ediff-buffer-live-p anc-buffer)
e756eb9f 1020 (ediff-with-current-buffer anc-buffer
4ad42cb5 1021 (goto-char (point-min))))
71296446 1022
e756eb9f 1023 (ediff-with-current-buffer diff-buffer
475f9031
KH
1024 (goto-char (point-min))
1025 (while (re-search-forward ediff-match-diff3-line nil t)
1026 ;; leave point after matched line
1027 (beginning-of-line 2)
1028 (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
bbe6126c 1029 ;; if the files A and B are the same and not 3way-comparison,
475f9031
KH
1030 ;; ignore the difference
1031 (if (or three-way-comp (not (string-equal agreement "3")))
1032 (let* ((a-begin (car (ediff-get-diff3-group "1")))
1033 (a-end (nth 1 (ediff-get-diff3-group "1")))
1034 (b-begin (car (ediff-get-diff3-group "2")))
1035 (b-end (nth 1 (ediff-get-diff3-group "2")))
4ad42cb5
MK
1036 (c-or-anc-begin (car (ediff-get-diff3-group "3")))
1037 (c-or-anc-end (nth 1 (ediff-get-diff3-group "3")))
475f9031
KH
1038 (state-of-merge
1039 (cond ((string-equal agreement "1") 'prefer-A)
1040 ((string-equal agreement "2") 'prefer-B)
1041 (t ediff-default-variant)))
1042 (state-of-diff-merge
1043 (if (memq state-of-merge '(default-A prefer-A)) 'B 'A))
1044 (state-of-diff-comparison
1045 (cond ((string-equal agreement "1") 'A)
1046 ((string-equal agreement "2") 'B)
1047 ((string-equal agreement "3") 'C)))
4ad42cb5 1048 state-of-ancestor
475f9031
KH
1049 c-begin c-end
1050 a-begin-pt a-end-pt
4ad42cb5
MK
1051 b-begin-pt b-end-pt
1052 c-begin-pt c-end-pt
1053 anc-begin-pt anc-end-pt)
71296446 1054
4ad42cb5
MK
1055 (setq state-of-ancestor
1056 (= c-or-anc-begin c-or-anc-end))
1057
1058 (cond (three-way-comp
1059 (setq c-begin c-or-anc-begin
1060 c-end c-or-anc-end))
1061 ((eq ediff-default-variant 'default-B)
1062 (setq c-begin b-begin
1063 c-end b-end))
1064 (t
1065 (setq c-begin a-begin
1066 c-end a-end)))
71296446 1067
475f9031
KH
1068 ;; compute main diff vector
1069 (if word-mode
1070 ;; make diff-list contain word numbers
50a07e18 1071 (setq diff-list
475f9031
KH
1072 (nconc diff-list
1073 (list (vector
1074 (- a-begin a-prev) (- a-end a-begin)
1075 (- b-begin b-prev) (- b-end b-begin)
1076 (- c-begin c-prev) (- c-end c-begin)
4ad42cb5
MK
1077 nil nil ; dummy ancestor
1078 nil ; state of diff
1079 nil ; state of merge
1080 nil ; state of ancestor
1081 )))
475f9031
KH
1082 a-prev a-end
1083 b-prev b-end
1084 c-prev c-end)
1085 ;; else convert lines to points
e756eb9f 1086 (ediff-with-current-buffer A-buffer
8ea74b0e
MK
1087 (let ((longlines-mode-val
1088 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
1089 ;; we must disable and then restore longlines-mode
1090 (if (eq longlines-mode-val 1)
1091 (longlines-mode 0))
1092 (forward-line (- a-begin a-prev))
1093 (setq a-begin-pt (point))
1094 (forward-line (- a-end a-begin))
1095 (setq a-end-pt (point)
1096 a-prev a-end)
1097 (if (eq longlines-mode-val 1)
1098 (longlines-mode longlines-mode-val))
1099 ))
e756eb9f 1100 (ediff-with-current-buffer B-buffer
8ea74b0e
MK
1101 (let ((longlines-mode-val
1102 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
1103 (if (eq longlines-mode-val 1)
1104 (longlines-mode 0))
1105 (forward-line (- b-begin b-prev))
1106 (setq b-begin-pt (point))
1107 (forward-line (- b-end b-begin))
1108 (setq b-end-pt (point)
1109 b-prev b-end)
1110 (if (eq longlines-mode-val 1)
1111 (longlines-mode longlines-mode-val))
1112 ))
e756eb9f 1113 (ediff-with-current-buffer C-buffer
8ea74b0e
MK
1114 (let ((longlines-mode-val
1115 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
1116 (if (eq longlines-mode-val 1)
1117 (longlines-mode 0))
1118 (forward-line (- c-begin c-prev))
1119 (setq c-begin-pt (point))
1120 (forward-line (- c-end c-begin))
1121 (setq c-end-pt (point)
1122 c-prev c-end)
1123 (if (eq longlines-mode-val 1)
1124 (longlines-mode longlines-mode-val))
1125 ))
4ad42cb5 1126 (if (ediff-buffer-live-p anc-buffer)
e756eb9f 1127 (ediff-with-current-buffer anc-buffer
8ea74b0e
MK
1128 (let ((longlines-mode-val
1129 (if (and (boundp 'longlines-mode) longlines-mode) 1 0)))
1130 (if (eq longlines-mode-val 1)
1131 (longlines-mode 0))
1132 (forward-line (- c-or-anc-begin anc-prev))
1133 (setq anc-begin-pt (point))
1134 (forward-line (- c-or-anc-end c-or-anc-begin))
1135 (setq anc-end-pt (point)
1136 anc-prev c-or-anc-end)
1137 (if (eq longlines-mode-val 1)
1138 (longlines-mode longlines-mode-val))
1139 )))
50a07e18 1140 (setq diff-list
475f9031
KH
1141 (nconc
1142 diff-list
1143 ;; if comparing with ancestor, then there also is a
1144 ;; state-of-difference marker
1145 (if three-way-comp
1146 (list (vector
1147 a-begin-pt a-end-pt
1148 b-begin-pt b-end-pt
1149 c-begin-pt c-end-pt
4ad42cb5 1150 nil nil ; ancestor begin/end
475f9031 1151 state-of-diff-comparison
4ad42cb5
MK
1152 nil ; state of merge
1153 nil ; state of ancestor
475f9031
KH
1154 ))
1155 (list (vector a-begin-pt a-end-pt
1156 b-begin-pt b-end-pt
1157 c-begin-pt c-end-pt
4ad42cb5 1158 anc-begin-pt anc-end-pt
475f9031
KH
1159 state-of-diff-merge
1160 state-of-merge
4ad42cb5 1161 state-of-ancestor
475f9031
KH
1162 )))
1163 )))
1164 ))
71296446 1165
e756eb9f 1166 ))) ; end ediff-with-current-buffer
475f9031
KH
1167 diff-list
1168 ))
71296446 1169
475f9031
KH
1170;; Generate the difference vector and overlays for three files
1171;; File-C is either the third file to compare (in case of 3-way comparison)
1172;; or it is the ancestor file.
1173(defun ediff-setup-diff-regions3 (file-A file-B file-C)
475f9031
KH
1174 (or (ediff-buffer-live-p ediff-diff-buffer)
1175 (setq ediff-diff-buffer
1176 (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*"))))
71296446 1177
4ad42cb5
MK
1178 (message "Computing differences ...")
1179 (ediff-exec-process ediff-diff3-program ediff-diff-buffer 'synchronize
1180 ediff-diff3-options file-A file-B file-C)
71296446 1181
475f9031 1182 (ediff-prepare-error-list ediff-diff3-ok-lines-regexp ediff-diff-buffer)
4ad42cb5 1183 ;;(message "Computing differences ... done")
475f9031
KH
1184 (ediff-convert-diffs-to-overlays
1185 (ediff-extract-diffs3
1186 ediff-diff-buffer
1187 ediff-word-mode ediff-3way-comparison-job ediff-narrow-bounds)
1188 ))
71296446 1189
475f9031 1190
4ae69eac 1191;; Execute PROGRAM asynchronously, unless OS/2, Windows-*, or DOS, or unless
e756eb9f
MK
1192;; SYNCH is non-nil. BUFFER must be a buffer object, and must be alive. The
1193;; OPTIONS arg is a list of options to pass to PROGRAM. It may be a blank
1194;; string. All elements in FILES must be strings. We also delete nil from
1195;; args.
1196(defun ediff-exec-process (program buffer synch options &rest files)
1197 (let ((data (match-data))
513bea45 1198 (coding-system-for-read ediff-coding-system-for-read)
e756eb9f
MK
1199 args)
1200 (setq args (append (split-string options) files))
1201 (setq args (delete "" (delq nil args))) ; delete nil and "" from arguments
7997f1ca 1202 ;; the --binary option, if present, should be used only for buffer jobs
560ef11a 1203 ;; or for refining the differences
7997f1ca 1204 (or (string-match "buffer" (symbol-name ediff-job-name))
560ef11a 1205 (eq buffer ediff-fine-diff-buffer)
7997f1ca 1206 (setq args (delete "--binary" args)))
475f9031
KH
1207 (unwind-protect
1208 (let ((directory default-directory)
1209 proc)
475f9031
KH
1210 (save-excursion
1211 (set-buffer buffer)
1212 (erase-buffer)
1213 (setq default-directory directory)
4ae69eac
MK
1214 (if (or (memq system-type '(emx ms-dos windows-nt windows-95))
1215 synch)
1216 ;; In OS/2 (emx) do it synchronously, since OS/2 doesn't let us
4ad42cb5
MK
1217 ;; delete files used by other processes. Thus, in ediff-buffers
1218 ;; and similar functions, we can't delete temp files because
4ae69eac 1219 ;; they might be used by the asynch process that computes
4ad42cb5
MK
1220 ;; custom diffs. So, we have to wait till custom diff
1221 ;; subprocess is done.
4ae69eac
MK
1222 ;; Similarly for Windows-*
1223 ;; In DOS, must synchronize because DOS doesn't have
1224 ;; asynchronous processes.
4ad42cb5
MK
1225 (apply 'call-process program nil buffer nil args)
1226 ;; On other systems, do it asynchronously.
1227 (setq proc (get-buffer-process buffer))
1228 (if proc (kill-process proc))
1229 (setq proc
1230 (apply 'start-process "Custom Diff" buffer program args))
1231 (setq mode-line-process '(":%s"))
1232 (set-process-sentinel proc 'ediff-process-sentinel)
1233 (set-process-filter proc 'ediff-process-filter)
1234 )))
2eb4bdca 1235 (store-match-data data))))
71296446 1236
863312cd 1237;; This is shell-command-filter from simple.el in Emacs.
475f9031 1238;; Copied here because XEmacs doesn't have it.
4ad42cb5 1239(defun ediff-process-filter (proc string)
475f9031
KH
1240 ;; Do save-excursion by hand so that we can leave point numerically unchanged
1241 ;; despite an insertion immediately after it.
1242 (let* ((obuf (current-buffer))
1243 (buffer (process-buffer proc))
1244 opoint
1245 (window (get-buffer-window buffer))
1246 (pos (window-start window)))
1247 (unwind-protect
1248 (progn
1249 (set-buffer buffer)
1250 (or (= (point) (point-max))
1251 (setq opoint (point)))
1252 (goto-char (point-max))
1253 (insert-before-markers string))
1254 ;; insert-before-markers moved this marker: set it back.
1255 (set-window-start window pos)
1256 ;; Finish our save-excursion.
1257 (if opoint
1258 (goto-char opoint))
1259 (set-buffer obuf))))
71296446 1260
475f9031
KH
1261;; like shell-command-sentinel but doesn't print an exit status message
1262;; we do this because diff always exits with status 1, if diffs are found
1263;; so shell-command-sentinel displays a confusing message to the user
4ad42cb5 1264(defun ediff-process-sentinel (process signal)
475f9031
KH
1265 (if (and (memq (process-status process) '(exit signal))
1266 (buffer-name (process-buffer process)))
1267 (progn
1268 (save-excursion
1269 (set-buffer (process-buffer process))
1270 (setq mode-line-process nil))
1271 (delete-process process))))
71296446 1272
475f9031 1273
50a07e18 1274;;; Word functions used to refine the current diff
475f9031
KH
1275
1276(defvar ediff-forward-word-function 'ediff-forward-word
1277 "*Function to call to move to the next word.
1278Used for splitting difference regions into individual words.")
743a79af 1279(make-variable-buffer-local 'ediff-forward-word-function)
475f9031
KH
1280
1281(defvar ediff-whitespace " \n\t\f"
1282 "*Characters constituting white space.
1283These characters are ignored when differing regions are split into words.")
743a79af 1284(make-variable-buffer-local 'ediff-whitespace)
475f9031 1285
50a07e18
MK
1286(defvar ediff-word-1
1287 (ediff-cond-compile-for-xemacs-or-emacs "a-zA-Z---_" "-[:word:]_")
475f9031
KH
1288 "*Characters that constitute words of type 1.
1289More precisely, [ediff-word-1] is a regexp that matches type 1 words.
50a07e18 1290See `ediff-forward-word' for more details.")
743a79af 1291(make-variable-buffer-local 'ediff-word-1)
475f9031
KH
1292
1293(defvar ediff-word-2 "0-9.,"
1294 "*Characters that constitute words of type 2.
1295More precisely, [ediff-word-2] is a regexp that matches type 2 words.
1296See `ediff-forward-word' for more details.")
743a79af 1297(make-variable-buffer-local 'ediff-word-2)
475f9031
KH
1298
1299(defvar ediff-word-3 "`'?!:;\"{}[]()"
1300 "*Characters that constitute words of type 3.
1301More precisely, [ediff-word-3] is a regexp that matches type 3 words.
1302See `ediff-forward-word' for more details.")
743a79af 1303(make-variable-buffer-local 'ediff-word-3)
475f9031
KH
1304
1305(defvar ediff-word-4
1306 (concat "^" ediff-word-1 ediff-word-2 ediff-word-3 ediff-whitespace)
1307 "*Characters that constitute words of type 4.
1308More precisely, [ediff-word-4] is a regexp that matches type 4 words.
50a07e18 1309See `ediff-forward-word' for more details.")
743a79af 1310(make-variable-buffer-local 'ediff-word-4)
475f9031
KH
1311
1312;; Split region along word boundaries. Each word will be on its own line.
1313;; Output to buffer out-buffer.
1314(defun ediff-forward-word ()
1315 "Move point one word forward.
1316There are four types of words, each of which consists entirely of
1317characters in `ediff-word-1', `ediff-word-2', `ediff-word-3', or
6de3983f
MK
1318`ediff-word-4'. Words are recognized by passing these one after another as
1319arguments to `skip-chars-forward'."
1320 (or (> (+ (skip-chars-forward ediff-word-1)
1321 (skip-syntax-forward "w"))
1322 0)
475f9031
KH
1323 (> (skip-chars-forward ediff-word-2) 0)
1324 (> (skip-chars-forward ediff-word-3) 0)
1325 (> (skip-chars-forward ediff-word-4) 0)
1326 ))
1327
d396e521 1328
475f9031 1329(defun ediff-wordify (beg end in-buffer out-buffer &optional control-buf)
50a07e18
MK
1330 (let ((forward-word-function
1331 ;; eval in control buf to let user create local versions for
1332 ;; different invocations
1333 (if control-buf
1334 (ediff-with-current-buffer control-buf
1335 ediff-forward-word-function)
1336 ediff-forward-word-function))
1337 inbuf-syntax-tbl sv-point diff-string)
475f9031
KH
1338 (save-excursion
1339 (set-buffer in-buffer)
4986c2c6
MK
1340 (setq inbuf-syntax-tbl
1341 (if control-buf
1342 (ediff-with-current-buffer control-buf
1343 ediff-syntax-table)
1344 (syntax-table)))
1345 (setq diff-string (buffer-substring-no-properties beg end))
475f9031
KH
1346
1347 (set-buffer out-buffer)
4696802b 1348 ;; Make sure that temp buff syntax table is the same as the original buf
d396e521
MK
1349 ;; syntax tbl, because we use ediff-forward-word in both and
1350 ;; ediff-forward-word depends on the syntax classes of characters.
1351 (set-syntax-table inbuf-syntax-tbl)
475f9031 1352 (erase-buffer)
4986c2c6 1353 (insert diff-string)
475f9031
KH
1354 (goto-char (point-min))
1355 (skip-chars-forward ediff-whitespace)
1356 (delete-region (point-min) (point))
71296446 1357
475f9031 1358 (while (not (eobp))
50a07e18 1359 (funcall forward-word-function)
475f9031
KH
1360 (setq sv-point (point))
1361 (skip-chars-forward ediff-whitespace)
1362 (delete-region sv-point (point))
1363 (insert "\n")))))
71296446 1364
50a07e18 1365;; copy string specified as BEG END from IN-BUF to OUT-BUF
475f9031 1366(defun ediff-copy-to-buffer (beg end in-buffer out-buffer)
50a07e18
MK
1367 (with-current-buffer out-buffer
1368 (erase-buffer)
1369 (insert-buffer-substring in-buffer beg end)
1370 (goto-char (point-min))))
475f9031
KH
1371
1372
1373;; goto word #n starting at current position in buffer `buf'
4986c2c6 1374;; For ediff, a word is determined by ediff-forward-word-function
475f9031
KH
1375;; If `flag' is non-nil, goto the end of the n-th word.
1376(defun ediff-goto-word (n buf &optional flag)
1377 ;; remember val ediff-forward-word-function has in ctl buf
4986c2c6
MK
1378 (let ((fwd-word-fun ediff-forward-word-function)
1379 (syntax-tbl ediff-syntax-table))
e756eb9f 1380 (ediff-with-current-buffer buf
475f9031 1381 (skip-chars-forward ediff-whitespace)
50a07e18
MK
1382 (ediff-with-syntax-table syntax-tbl
1383 (while (> n 1)
1384 (funcall fwd-word-fun)
1385 (skip-chars-forward ediff-whitespace)
17561e4f
MK
1386 (setq n (1- n)))
1387 (if (and flag (> n 0))
1388 (funcall fwd-word-fun)))
475f9031
KH
1389 (point))))
1390
328b4b70 1391(defun ediff-same-file-contents (f1 f2)
17561e4f
MK
1392 "Return t if files F1 and F2 have identical contents."
1393 (if (and (not (file-directory-p f1))
1394 (not (file-directory-p f2)))
1395 (let ((res
1396 (apply 'call-process ediff-cmp-program nil nil nil
1397 (append ediff-cmp-options (list f1 f2)))))
1398 (and (numberp res) (eq res 0))))
1399 )
1400
1401
1402(defun ediff-same-contents (d1 d2 &optional filter-re)
1403 "Returns t iff D1 and D2 have the same content.
1404D1 and D2 can either be both directories or both regular files.
1405Symlinks and the likes are not handled.
1406If FILTER-RE is non-nil, recursive checking in directories
1407affects only files whose names match the expression."
1408 ;; Normalize empty filter RE to nil.
899a431b 1409 (unless (> (length filter-re) 0) (setq filter-re nil))
17561e4f
MK
1410 ;; Indicate progress
1411 (message "Comparing '%s' and '%s' modulo '%s'" d1 d2 filter-re)
1412 (cond
1413 ;; D1 & D2 directories => recurse
1414 ((and (file-directory-p d1)
1415 (file-directory-p d2))
1416 (if (null ediff-recurse-to-subdirectories)
1417 (if (y-or-n-p "Compare subdirectories recursively? ")
1418 (setq ediff-recurse-to-subdirectories 'yes)
1419 (setq ediff-recurse-to-subdirectories 'no)))
1420 (if (eq ediff-recurse-to-subdirectories 'yes)
1421 (let* ((all-entries-1 (directory-files d1 t filter-re))
1422 (all-entries-2 (directory-files d2 t filter-re))
899a431b
MK
1423 (entries-1 (ediff-delete-all-matches "^\\.\\.?$" all-entries-1))
1424 (entries-2 (ediff-delete-all-matches "^\\.\\.?$" all-entries-2))
17561e4f 1425 )
899a431b
MK
1426
1427 (ediff-same-file-contents-lists entries-1 entries-2 filter-re)
17561e4f
MK
1428 ))
1429 ) ; end of the directories case
1430 ;; D1 & D2 are both files => compare directly
1431 ((and (file-regular-p d1)
1432 (file-regular-p d2))
1433 (ediff-same-file-contents d1 d2))
1434 ;; Otherwise => false: unequal contents
1435 )
1436 )
328b4b70 1437
899a431b
MK
1438;; If lists have the same length and names of files are pairwise equal
1439;; (removing the directories) then compare contents pairwise.
1440;; True if all contents are the same; false otherwise
1441(defun ediff-same-file-contents-lists (entries-1 entries-2 filter-re)
1442 ;; First, check only the names (works quickly and ensures a
1443 ;; precondition for subsequent code)
1444 (if (and (= (length entries-1) (length entries-2))
1445 (equal (mapcar 'file-name-nondirectory entries-1)
1446 (mapcar 'file-name-nondirectory entries-2)))
1447 ;; With name equality established, compare the entries
1448 ;; through recursion.
1449 (let ((continue t))
1450 (while (and entries-1 continue)
1451 (if (ediff-same-contents
1452 (car entries-1) (car entries-2) filter-re)
1453 (setq entries-1 (cdr entries-1)
1454 entries-2 (cdr entries-2))
1455 (setq continue nil))
1456 )
1457 ;; if reached the end then lists are equal
1458 (null entries-1))
1459 )
1460 )
1461
1462
1463;; ARG1 is a regexp, ARG2 is a list of full-filenames
1464;; Delete all entries that match the regexp
1465(defun ediff-delete-all-matches (regex file-list-list)
1466 (let (result elt)
1467 (while file-list-list
1468 (setq elt (car file-list-list))
1469 (or (string-match regex (file-name-nondirectory elt))
1470 (setq result (cons elt result)))
1471 (setq file-list-list (cdr file-list-list)))
1472 (reverse result)))
1473
475f9031 1474
bbe6126c
MK
1475;;; Local Variables:
1476;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
1477;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
1478;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
bbe6126c
MK
1479;;; End:
1480
ab5796a9 1481;;; arch-tag: a86d448e-58d7-4572-a1d9-fdedfa22f648
3afbc435 1482;;; ediff-diff.el ends here