(scan_sexps_forward): Fix previous change.
[bpt/emacs.git] / lisp / ediff-util.el
CommitLineData
475f9031 1;;; ediff-util.el --- the core commands and utilities of ediff
732be465 2;;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
475f9031
KH
3
4;; Author: Michael Kifer <kifer@cs.sunysb.edu>
5
6;; This file is part of GNU Emacs.
7
8;; GNU Emacs is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 2, or (at your option)
11;; any later version.
12
13;; GNU Emacs is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with GNU Emacs; see the file COPYING. If not, write to
20;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
21
22
23;;; Code:
24
25(require 'ediff-init)
26
27\f
28;;; Functions
29
30(defun ediff-mode ()
31 "Ediff mode is used by the Ediff file-difference package.
32It is entered only through one of the following commands:
33 `ediff'
34 `ediff-files'
35 `ediff-buffers'
36 `ediff3'
37 `ediff-files3'
38 `ediff-buffers3'
39 `ediff-merge'
40 `ediff-merge-files'
41 `ediff-merge-files-with-ancestor'
42 `ediff-merge-buffers'
43 `ediff-merge-buffers-with-ancestor'
44 `ediff-merge-revisions'
45 `ediff-merge-revisions-with-ancestor'
41d25ad0
KH
46 `ediff-windows-wordwise'
47 `ediff-windows-linewise'
48 `ediff-regions-wordwise'
49 `ediff-regions-linewise'
475f9031
KH
50 `epatch'
51 `ediff-patch-file'
52 `ediff-patch-buffer'
53 `epatch-buffer'
54 `ediff-revision'
55
56Commands:
57\\{ediff-mode-map}"
58 (kill-all-local-variables)
59 (setq major-mode 'ediff-mode)
60 (setq mode-name "Ediff")
61 (run-hooks 'ediff-mode-hooks))
62
63(defun ediff-version ()
64 "Return string describing the version of Ediff.
65When called interactively, displays the version."
66 (interactive)
67 (if (interactive-p)
68 (message (ediff-version))
69 (format "Ediff %s of %s" ediff-version ediff-date)))
70
71
72(require 'ediff-diff)
73(require 'ediff-merg)
74
75\f
76;;; Build keymaps
77
78(ediff-defvar-local ediff-mode-map nil
79 "Local keymap used in Ediff mode.
80This is local to each Ediff Control Panel, so they may vary from invocation
81to invocation.")
82
83;; Set up the keymap in the control buffer
84(defun ediff-set-keys ()
85 "Set up Ediff keymap, if necessary."
86 (if (null ediff-mode-map)
87 (ediff-setup-keymap))
88 (use-local-map ediff-mode-map))
89
90;; Reload Ediff keymap. For debugging only.
91(defun ediff-reload-keymap ()
92 (interactive)
93 (setq ediff-mode-map nil)
94 (ediff-set-keys))
95
96
97(defun ediff-setup-keymap ()
98 "Set up the keymap used in the control buffer of Ediff."
99 (setq ediff-mode-map (make-sparse-keymap))
100 (suppress-keymap ediff-mode-map)
101
102 (define-key ediff-mode-map "p" 'ediff-previous-difference)
103 (define-key ediff-mode-map "\C-?" 'ediff-previous-difference)
104 (define-key ediff-mode-map [backspace] 'ediff-previous-difference)
105 (define-key ediff-mode-map [delete] 'ediff-previous-difference)
106 (define-key ediff-mode-map "\C-h" (if ediff-no-emacs-help-in-control-buffer
107 'ediff-previous-difference nil))
ec3ea488
RS
108 (define-key ediff-mode-map [f1] (if ediff-no-emacs-help-in-control-buffer
109 'ediff-previous-difference nil))
110 (define-key ediff-mode-map [help] (if ediff-no-emacs-help-in-control-buffer
111 'ediff-previous-difference nil))
475f9031
KH
112 (define-key ediff-mode-map "n" 'ediff-next-difference)
113 (define-key ediff-mode-map " " 'ediff-next-difference)
114 (define-key ediff-mode-map "j" 'ediff-jump-to-difference)
115 (define-key ediff-mode-map "g" nil)
116 (define-key ediff-mode-map "ga" 'ediff-jump-to-difference-at-point)
117 (define-key ediff-mode-map "gb" 'ediff-jump-to-difference-at-point)
118 (define-key ediff-mode-map "q" 'ediff-quit)
119 (define-key ediff-mode-map "z" 'ediff-suspend)
120 (define-key ediff-mode-map "\C-l" 'ediff-recenter)
121 (define-key ediff-mode-map "|" 'ediff-toggle-split)
122 (define-key ediff-mode-map "h" 'ediff-toggle-hilit)
123 (or ediff-word-mode
124 (define-key ediff-mode-map "@" 'ediff-toggle-autorefine))
41d25ad0 125 (if ediff-narrow-job
475f9031
KH
126 (define-key ediff-mode-map "%" 'ediff-toggle-narrow-region))
127 (define-key ediff-mode-map "~" 'ediff-swap-buffers)
128 (define-key ediff-mode-map "v" 'ediff-scroll-vertically)
129 (define-key ediff-mode-map "\C-v" 'ediff-scroll-vertically)
130 (define-key ediff-mode-map "^" 'ediff-scroll-vertically)
131 (define-key ediff-mode-map "\M-v" 'ediff-scroll-vertically)
132 (define-key ediff-mode-map "V" 'ediff-scroll-vertically)
133 (define-key ediff-mode-map "<" 'ediff-scroll-horizontally)
134 (define-key ediff-mode-map ">" 'ediff-scroll-horizontally)
135 (define-key ediff-mode-map "i" 'ediff-status-info)
41d25ad0 136 (define-key ediff-mode-map "D" 'ediff-documentation)
475f9031
KH
137 (define-key ediff-mode-map "?" 'ediff-toggle-help)
138 (define-key ediff-mode-map "!" 'ediff-update-diffs)
139 (or ediff-word-mode
140 (define-key ediff-mode-map "*" 'ediff-make-or-kill-fine-diffs))
141 (define-key ediff-mode-map "a" nil)
142 (define-key ediff-mode-map "b" nil)
143 (define-key ediff-mode-map "r" nil)
144 (cond (ediff-merge-job
145 ;; In merging, we allow only A->C and B->C copying.
146 (define-key ediff-mode-map "a" (function
147 (lambda (arg)
148 (interactive "P")
149 (ediff-diff-to-diff arg "ac"))))
150 (define-key ediff-mode-map "b" (function
151 (lambda (arg)
152 (interactive "P")
153 (ediff-diff-to-diff arg "bc"))))
154 (define-key ediff-mode-map "r" (function
155 (lambda (arg)
156 (interactive "P")
157 (ediff-restore-diff arg ?c))))
158 (define-key ediff-mode-map "s" 'ediff-shrink-window-C)
159 (define-key ediff-mode-map "+" 'ediff-combine-diffs)
160 (define-key ediff-mode-map "$" 'ediff-toggle-show-clashes-only)
161 (define-key ediff-mode-map "&" 'ediff-re-merge))
162 (ediff-3way-comparison-job
163 (define-key ediff-mode-map "ab" 'ediff-diff-to-diff)
164 (define-key ediff-mode-map "ba" 'ediff-diff-to-diff)
165 (define-key ediff-mode-map "ac" 'ediff-diff-to-diff)
166 (define-key ediff-mode-map "bc" 'ediff-diff-to-diff)
167 (define-key ediff-mode-map "c" nil)
168 (define-key ediff-mode-map "ca" 'ediff-diff-to-diff)
169 (define-key ediff-mode-map "cb" 'ediff-diff-to-diff)
170 (define-key ediff-mode-map "ra" 'ediff-restore-diff)
171 (define-key ediff-mode-map "rb" 'ediff-restore-diff)
172 (define-key ediff-mode-map "rc" 'ediff-restore-diff)
173 (define-key ediff-mode-map "C" 'ediff-toggle-read-only))
174 (t ; 2-way comparison
175 (define-key ediff-mode-map "a" (function
176 (lambda (arg)
177 (interactive "P")
178 (ediff-diff-to-diff arg "ab"))))
179 (define-key ediff-mode-map "b" (function
180 (lambda (arg)
181 (interactive "P")
182 (ediff-diff-to-diff arg "ba"))))
183 (define-key ediff-mode-map "ra" 'ediff-restore-diff)
184 (define-key ediff-mode-map "rb" 'ediff-restore-diff))
185 ) ; cond
186 (define-key ediff-mode-map "G" 'ediff-submit-report)
187 (define-key ediff-mode-map "#" nil)
188 (define-key ediff-mode-map "#h" 'ediff-toggle-regexp-match)
189 (define-key ediff-mode-map "#f" 'ediff-toggle-regexp-match)
190 (or ediff-word-mode
191 (define-key ediff-mode-map "##" 'ediff-toggle-skip-similar))
192 (define-key ediff-mode-map "o" nil)
193 (define-key ediff-mode-map "A" 'ediff-toggle-read-only)
194 (define-key ediff-mode-map "B" 'ediff-toggle-read-only)
195 (define-key ediff-mode-map "w" nil)
196 (define-key ediff-mode-map "wa" 'ediff-save-buffer)
197 (define-key ediff-mode-map "wb" 'ediff-save-buffer)
198 (define-key ediff-mode-map "wd" 'ediff-save-buffer)
199 (if ediff-3way-job
200 (progn
201 (define-key ediff-mode-map "wc" 'ediff-save-buffer)
202 (define-key ediff-mode-map "gc" 'ediff-jump-to-difference-at-point)
203 ))
204
205 (define-key ediff-mode-map "m" 'ediff-toggle-wide-display)
206
207 (define-key ediff-mode-map "k" nil)
208 (define-key ediff-mode-map "kkk" 'ediff-reload-keymap) ; for debugging
209
210 ;; Allow ediff-mode-map to be referenced indirectly
211 (fset 'ediff-mode-map ediff-mode-map)
212 (run-hooks 'ediff-keymap-setup-hooks))
213
214
215;;; Setup functions
216
217(require 'ediff-wind)
218
219;; Common startup entry for all Ediff functions
41d25ad0 220;; It now returns control buffer so other functions can do post-processing
475f9031
KH
221(defun ediff-setup (buffer-A file-A buffer-B file-B buffer-C file-C
222 startup-hooks setup-parameters)
223 (setq file-A (expand-file-name file-A))
224 (setq file-B (expand-file-name file-B))
225 (if (stringp file-C)
226 (setq file-C (expand-file-name file-C)))
227 (let* ((control-buffer-name
228 (ediff-unique-buffer-name "*Ediff Control Panel" "*"))
229 (control-buffer (ediff-eval-in-buffer buffer-A
230 (get-buffer-create control-buffer-name))))
231 (ediff-eval-in-buffer control-buffer
232 (ediff-mode)
233
234 ;; unwrap set up parameters passed as argument
235 (while setup-parameters
236 (set (car (car setup-parameters)) (cdr (car setup-parameters)))
237 (setq setup-parameters (cdr setup-parameters)))
238
239 ;; set variables classifying the current ediff job
240 (setq ediff-3way-comparison-job (ediff-3way-comparison-job)
241 ediff-merge-job (ediff-merge-job)
242 ediff-merge-with-ancestor-job (ediff-merge-with-ancestor-job)
243 ediff-3way-job (ediff-3way-job)
244 ediff-diff3-job (ediff-diff3-job)
41d25ad0
KH
245 ediff-narrow-job (ediff-narrow-job)
246 ediff-windows-job (ediff-windows-job)
475f9031
KH
247 ediff-word-mode-job (ediff-word-mode-job))
248
249 (make-local-variable 'ediff-prefer-long-help-message)
250 (make-local-variable 'ediff-prefer-iconified-control-frame)
251 (make-local-variable 'ediff-split-window-function)
252 (make-local-variable 'ediff-default-variant)
253 (make-local-variable 'ediff-merge-window-share)
41d25ad0 254 (make-local-variable 'ediff-window-setup-function)
475f9031
KH
255
256 ;; adjust for merge jobs
257 (if ediff-merge-job
258 (let ((buf
259 ;; Use buf A even if `combined'. The right stuff is
260 ;; inserted by ediff-do-merge
261 (if (eq ediff-default-variant 'default-B) buffer-B buffer-A)))
262
263 (setq ediff-split-window-function
264 ediff-merge-split-window-function)
265
266 ;; remember the ancestor buffer, if any
267 (setq ediff-ancestor-buffer buffer-C)
268
269 (setq buffer-C
270 (get-buffer-create
271 (ediff-unique-buffer-name "*ediff-merge" "*")))
272 (save-excursion
273 (set-buffer buffer-C)
41d25ad0
KH
274 (insert-buffer buf)
275 (funcall (ediff-eval-in-buffer buf major-mode))
276 ;; after Stig@hackvan.com
277 (add-hook 'local-write-file-hooks 'ediff-set-merge-mode)
278 )))
475f9031
KH
279 (setq buffer-read-only nil
280 ediff-buffer-A buffer-A
281 ediff-buffer-B buffer-B
282 ediff-buffer-C buffer-C
283 ediff-control-buffer control-buffer)
284
285 (setq ediff-control-buffer-suffix
286 (if (string-match "<[0-9]*>" control-buffer-name)
287 (substring control-buffer-name
288 (match-beginning 0) (match-end 0))
289 "")
290 ediff-control-buffer-number
291 (max
292 0
293 (1-
294 (string-to-number
295 (substring
296 ediff-control-buffer-suffix
297 (or
298 (string-match "[0-9]+" ediff-control-buffer-suffix)
299 0))))))
300
301 (setq ediff-error-buffer (get-buffer-create (ediff-unique-buffer-name
302 "*ediff-errors" "*")))
303
304 (ediff-eval-in-buffer buffer-A (ediff-strip-mode-line-format))
305 (ediff-eval-in-buffer buffer-B (ediff-strip-mode-line-format))
306 (if ediff-3way-job
307 (ediff-eval-in-buffer buffer-C (ediff-strip-mode-line-format)))
308
309 (ediff-save-protected-variables) ; save variables to be restored on exit
310
475f9031
KH
311 ;; ediff-setup-diff-regions-function must be set after setup
312 ;; parameters are processed.
313 (setq ediff-setup-diff-regions-function
314 (if ediff-diff3-job
315 'ediff-setup-diff-regions3
316 'ediff-setup-diff-regions))
41d25ad0 317
475f9031
KH
318 (setq ediff-wide-bounds
319 (list (ediff-make-bullet-proof-overlay
320 '(point-min) '(point-max) ediff-buffer-A)
321 (ediff-make-bullet-proof-overlay
322 '(point-min) '(point-max) ediff-buffer-B)
323 (ediff-make-bullet-proof-overlay
324 '(point-min) '(point-max) ediff-buffer-C)))
325
326 ;; This has effect only on ediff-windows/regions
327 ;; In all other cases, ediff-visible-region sets visibility bounds to
328 ;; ediff-wide-bounds, and ediff-narrow-bounds are ignored.
329 (if ediff-start-narrowed
330 (setq ediff-visible-bounds ediff-narrow-bounds)
331 (setq ediff-visible-bounds ediff-wide-bounds))
332
333 (ediff-set-keys) ; comes after parameter setup
334
335 ;; set up ediff-narrow-bounds, if not set
336 (or ediff-narrow-bounds
337 (setq ediff-narrow-bounds ediff-wide-bounds))
338
475f9031
KH
339 ;; All these must be inside ediff-eval-in-buffer control-buffer,
340 ;; since these vars are local to control-buffer
341 ;; These won't run if there are errors in diff
342 (ediff-eval-in-buffer ediff-buffer-A
343 (ediff-nuke-selective-display)
344 (run-hooks 'ediff-prepare-buffer-hooks)
345 (if (ediff-eval-in-buffer control-buffer ediff-merge-job)
346 (setq buffer-read-only t))
41d25ad0
KH
347 ;; add control-buffer to the list of sessions--no longer used, but may
348 ;; be used again in the future
475f9031
KH
349 (or (memq control-buffer ediff-this-buffer-control-sessions)
350 (setq ediff-this-buffer-control-sessions
351 (cons control-buffer ediff-this-buffer-control-sessions)))
352 )
353 (ediff-eval-in-buffer ediff-buffer-B
354 (ediff-nuke-selective-display)
355 (run-hooks 'ediff-prepare-buffer-hooks)
356 (if (ediff-eval-in-buffer control-buffer ediff-merge-job)
357 (setq buffer-read-only t))
475f9031
KH
358 ;; add control-buffer to the list of sessions
359 (or (memq control-buffer ediff-this-buffer-control-sessions)
360 (setq ediff-this-buffer-control-sessions
361 (cons control-buffer ediff-this-buffer-control-sessions)))
362 )
363 (if ediff-3way-job
364 (ediff-eval-in-buffer ediff-buffer-C
365 (ediff-nuke-selective-display)
366 (run-hooks 'ediff-prepare-buffer-hooks)
475f9031
KH
367 ;; add control-buffer to the list of sessions
368 (or (memq control-buffer ediff-this-buffer-control-sessions)
369 (setq ediff-this-buffer-control-sessions
370 (cons control-buffer
371 ediff-this-buffer-control-sessions)))
372 ))
373
374 ;; must come after setting up ediff-narrow-bounds AND after
375 ;; nuking selective display
376 (funcall ediff-setup-diff-regions-function file-A file-B file-C)
377 (setq ediff-number-of-differences (length ediff-difference-vector-A))
378 (setq ediff-current-difference -1)
379
380 (ediff-make-current-diff-overlay 'A)
381 (ediff-make-current-diff-overlay 'B)
382 (if ediff-3way-job
383 (ediff-make-current-diff-overlay 'C))
384
41d25ad0 385 (if (ediff-window-display-p)
475f9031
KH
386 (ediff-init-var-faces))
387
388 (ediff-setup-windows buffer-A buffer-B buffer-C control-buffer)
389
390 (let ((shift-A (ediff-overlay-start
391 (ediff-get-value-according-to-buffer-type
392 'A ediff-narrow-bounds)))
393 (shift-B (ediff-overlay-start
394 (ediff-get-value-according-to-buffer-type
395 'B ediff-narrow-bounds)))
396 (shift-C (ediff-overlay-start
397 (ediff-get-value-according-to-buffer-type
398 'C ediff-narrow-bounds))))
399 ;; position point in buf A
400 (save-excursion
401 (select-window ediff-window-A)
402 (goto-char shift-A))
403 ;; position point in buf B
404 (save-excursion
405 (select-window ediff-window-B)
406 (goto-char shift-B))
407 (if ediff-3way-job
408 (save-excursion
409 (select-window ediff-window-C)
410 (goto-char shift-C)))
411 )
412
413 (select-window ediff-control-window)
414 (ediff-visible-region)
415
416 ;; The following is a hack to placate OS/2
417 ;; The problem is that OS/2 doesn't let us delete files used by other
418 ;; processes. Thus, in ediff-buffers and other functions, we can't
419 ;; delete temp files because they might be used by the asynchronous
420 ;; process that computes custom diffs. So, under OS/1 we have to wait
421 ;; for some time until custom diffs are done.
422 (if (eq system-type 'emx)
423 (ediff-eval-in-buffer ediff-custom-diff-buffer
424 (let ((proc (get-buffer-process (current-buffer))))
425 (while (and (processp proc)
426 (eq (process-status proc) 'run))
427 (message "Waiting for the diff program to quit")
41d25ad0 428 (sleep-for 1))
475f9031
KH
429 (message "")
430 )))
431
432 (run-hooks 'startup-hooks 'ediff-startup-hooks)
433 (ediff-refresh-mode-lines)
41d25ad0
KH
434 (setq buffer-read-only t))
435 control-buffer))
475f9031
KH
436
437
438;; This function assumes that we are in the window where control buffer is
439;; to reside.
440(defun ediff-setup-control-buffer (ctl-buf)
441 "Set up window for control buffer."
442 (if (window-dedicated-p (selected-window))
443 (set-buffer ctl-buf) ; we are in control frame but just in case
444 (switch-to-buffer ctl-buf))
41d25ad0 445 (let ((window-min-height 2))
475f9031
KH
446 (erase-buffer)
447 (ediff-set-help-message)
448 (insert ediff-help-message)
449 (shrink-window-if-larger-than-buffer)
41d25ad0 450 (or (ediff-multiframe-setup-p)
475f9031
KH
451 (ediff-indent-help-message))
452 (set-buffer-modified-p nil)
453 (ediff-refresh-mode-lines)
454 (setq ediff-control-window (selected-window))
455 (setq ediff-window-config-saved
41d25ad0 456 (format "%S%S%S%S%S%S%S"
475f9031
KH
457 ediff-control-window
458 ediff-window-A
459 ediff-window-B
460 ediff-window-C
41d25ad0
KH
461 ediff-split-window-function
462 (ediff-multiframe-setup-p)
463 ediff-wide-display-p))
475f9031
KH
464 (goto-char (point-min))
465 (skip-chars-forward ediff-whitespace)))
466
467;; assuming we are in control window, calculate length of the first line in
468;; help message
469(defun ediff-help-message-line-length ()
470 (save-excursion
471 (goto-char (point-min))
472 (if ediff-prefer-long-help-message
473 (next-line 1))
474 (end-of-line)
475 (current-column)))
476
477
478(defun ediff-indent-help-message ()
41d25ad0 479 (let* ((shift (/ (max 0 (- (window-width (selected-window))
475f9031
KH
480 (ediff-help-message-line-length)))
481 2))
482 (str (make-string shift ?\ )))
483 (save-excursion
484 (goto-char (point-min))
485 (while (< (point) (point-max))
486 (insert str)
487 (beginning-of-line)
488 (forward-line 1)))))
489
490
491(defun ediff-set-help-message ()
492 (setq ediff-long-help-message
493 (cond ((and ediff-long-help-message-custom
494 (or (symbolp ediff-long-help-message-custom)
495 (consp ediff-long-help-message-custom)))
496 (funcall ediff-long-help-message-custom))
497 (ediff-word-mode
498 (concat ediff-long-help-message-head
499 ediff-long-help-message-word-mode
500 ediff-long-help-message-tail))
41d25ad0
KH
501 (ediff-narrow-job
502 (concat ediff-long-help-message-head
503 ediff-long-help-message-narrow2
504 ediff-long-help-message-tail))
475f9031
KH
505 (ediff-merge-job
506 (concat ediff-long-help-message-head
507 ediff-long-help-message-merge
508 ediff-long-help-message-tail))
509 (ediff-diff3-job
510 (concat ediff-long-help-message-head
511 ediff-long-help-message-compare3
512 ediff-long-help-message-tail))
513 (t
514 (concat ediff-long-help-message-head
515 ediff-long-help-message-compare2
516 ediff-long-help-message-tail))))
517 (setq ediff-brief-help-message
518 (cond ((and ediff-brief-help-message-custom
519 (or (symbolp ediff-brief-help-message-custom)
520 (consp ediff-brief-help-message-custom)))
521 (funcall ediff-brief-help-message-custom))
522 ((stringp ediff-brief-help-message-custom)
523 ediff-brief-help-message-custom)
524 ((ediff-multiframe-setup-p) ediff-brief-message-string)
525 (t ; long brief msg, not multiframe --- put in the middle
526 ediff-brief-message-string)
527 ))
528 (setq ediff-help-message (if ediff-prefer-long-help-message
529 ediff-long-help-message
530 ediff-brief-help-message))
531 (run-hooks 'ediff-display-help-hooks)
532 )
533
534
535
536\f
537;;; Commands for working with Ediff
538
539(defun ediff-update-diffs ()
540 "Recompute difference regions in buffers A, B, and C.
541Buffers are not synchronized with their respective files, so changes done
542to these buffers are not saved at this point---the user can do this later,
543if necessary."
544 (interactive)
545 (let ((point-A (ediff-eval-in-buffer ediff-buffer-A (point)))
546 ;;(point-B (ediff-eval-in-buffer ediff-buffer-B (point)))
547 (tmp-buffer (get-buffer-create ediff-tmp-buffer))
548 (buf-A-file-name
549 (file-name-nondirectory (or (buffer-file-name ediff-buffer-A)
550 (buffer-name ediff-buffer-A)
551 )))
552 (buf-B-file-name
553 (file-name-nondirectory (or (buffer-file-name ediff-buffer-B)
554 (buffer-name ediff-buffer-B)
555 )))
556 (buf-C-file-name
557 (file-name-nondirectory (or (buffer-file-name ediff-buffer-C)
558 ;; if (null ediff-buffer-C), there is
559 ;; no danger, since we later check if
560 ;; ediff-buffer-C is alive
561 (buffer-name ediff-buffer-C)
562 )))
563 (overl-A (ediff-get-value-according-to-buffer-type
564 'A ediff-narrow-bounds))
565 (overl-B (ediff-get-value-according-to-buffer-type
566 'B ediff-narrow-bounds))
567 (overl-C (ediff-get-value-according-to-buffer-type
568 'C ediff-narrow-bounds))
569 beg-A end-A beg-B end-B beg-C end-C
570 file-A file-B file-C)
571 (ediff-unselect-and-select-difference -1)
572
573 (setq beg-A (ediff-overlay-start overl-A)
574 beg-B (ediff-overlay-start overl-B)
575 beg-C (ediff-overlay-start overl-C)
576 end-A (ediff-overlay-end overl-A)
577 end-B (ediff-overlay-end overl-B)
578 end-C (ediff-overlay-end overl-C))
579
580 (if ediff-word-mode
581 (progn
582 (ediff-wordify beg-A end-A ediff-buffer-A tmp-buffer)
583 (ediff-eval-in-buffer tmp-buffer
584 (setq file-A (ediff-make-temp-file "regA")))
585 (ediff-wordify beg-B end-B ediff-buffer-B tmp-buffer)
586 (ediff-eval-in-buffer tmp-buffer
587 (setq file-B (ediff-make-temp-file "regB")))
588 (if ediff-3way-job
589 (progn
590 (ediff-wordify beg-C end-C ediff-buffer-C tmp-buffer)
591 (ediff-eval-in-buffer tmp-buffer
592 (setq file-C (ediff-make-temp-file "regC")))))
593 )
594 ;; not word-mode
595 (ediff-eval-in-buffer ediff-buffer-A
596 (setq file-A (ediff-make-temp-file buf-A-file-name)))
597 (ediff-eval-in-buffer ediff-buffer-B
598 (setq file-B (ediff-make-temp-file buf-B-file-name)))
599 (if ediff-3way-job
600 (ediff-eval-in-buffer ediff-buffer-C
601 (setq file-C (ediff-make-temp-file buf-C-file-name))))
602 )
603
604 (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also)
605 (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also)
606 (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also)
607 (setq ediff-killed-diffs-alist nil) ; invalidate saved killed diff regions
608
609 ;; In case of merge job, full it into thinking that it is just doing
610 ;; comparison
611 (let ((ediff-setup-diff-regions-function ediff-setup-diff-regions-function)
612 (ediff-job-name ediff-job-name))
613 (if ediff-merge-job
614 (setq ediff-setup-diff-regions-function 'ediff-setup-diff-regions3
615 ediff-job-name 'ediff-files3))
616 (funcall ediff-setup-diff-regions-function file-A file-B file-C))
617
618 (setq ediff-number-of-differences (length ediff-difference-vector-A))
619 (delete-file file-A)
620 (delete-file file-B)
621 (if file-C
622 (delete-file file-C))
623
624 (if ediff-3way-job
625 (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer))
626
627 (ediff-jump-to-difference (ediff-diff-at-point 'A point-A))
628 (message "")
629 ))
630
631;; Not bound to any key---to dangerous. A user can do it if necessary.
632(defun ediff-revert-buffers-then-recompute-diffs (noconfirm)
633 "Revert buffers A, B and C. Then rerun Ediff on file A and file B."
634 (interactive "P")
635 (let ((bufA ediff-buffer-A)
636 (bufB ediff-buffer-B)
637 (bufC ediff-buffer-C)
638 (ctl-buf ediff-control-buffer)
639 (ancestor-buf ediff-ancestor-buffer)
640 (ancestor-job ediff-merge-with-ancestor-job)
641 (merge ediff-merge-job)
642 (comparison ediff-3way-comparison-job))
643 (ediff-eval-in-buffer bufA
644 (revert-buffer t noconfirm))
645 (ediff-eval-in-buffer bufB
646 (revert-buffer t noconfirm))
647 ;; this should only be executed in a 3way comparison, not in merge
648 (if comparison
649 (ediff-eval-in-buffer bufC
650 (revert-buffer t noconfirm)))
651 (if merge
652 (progn
653 (set-buffer ctl-buf)
654 (ediff-really-quit)
655 (kill-buffer bufC)
656 (if ancestor-job
657 (ediff-merge-buffers-with-ancestor bufA bufB ancestor-buf)
658 (ediff-merge-buffers bufA bufB)))
659 (ediff-update-diffs))))
660
661
662;; optional NO-REHIGHLIGHT says to not rehighlight buffers
663(defun ediff-recenter (&optional no-rehighlight)
664 "Bring the highlighted region of all buffers being compared into view.
665Reestablish the default three-window display."
666 (interactive)
667
668 ;; force all minibuffer to display ediff's messages.
41d25ad0 669 ;; when xemacs implements minibufferless frames, this won't be necessary
475f9031
KH
670 (if ediff-xemacs-p (setq synchronize-minibuffers t))
671
672 (setq ediff-disturbed-overlays nil) ; clear after use
673 (let (buffer-read-only)
674 (if (and (ediff-buffer-live-p ediff-buffer-A)
675 (ediff-buffer-live-p ediff-buffer-B)
676 (or (not ediff-3way-job)
41d25ad0 677 (ediff-buffer-live-p ediff-buffer-C)))
475f9031
KH
678 (ediff-setup-windows
679 ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-control-buffer)
680 (or (eq this-command 'ediff-quit)
681 (message
682 "You've killed an essential Ediff buffer---Please quit Ediff"
683 (beep 1)))
684 ))
685
686 ;; set visibility range appropriate to this invocation of Ediff.
687 (ediff-visible-region)
688
689 ;; raise
41d25ad0 690 (if (and (ediff-window-display-p)
475f9031
KH
691 (symbolp this-command)
692 (symbolp last-command)
693 ;; Either one of the display-changing commands
694 (or (memq this-command
695 '(ediff-recenter
696 ediff-toggle-wide-display ediff-toggle-multiframe))
697 ;; Or one of the movement cmds and prev cmd was an Ediff cmd
698 ;; This avoids rasing frames unnecessarily.
699 (and (memq this-command
700 '(ediff-next-difference
701 ediff-previous-difference
702 ediff-jump-to-difference
703 ediff-jump-to-difference-at-point))
704 (not (string-match "^ediff-" (symbol-name last-command)))
705 )))
706 (progn
707 (if (window-live-p ediff-window-A)
41d25ad0 708 (raise-frame (window-frame ediff-window-A)))
475f9031 709 (if (window-live-p ediff-window-B)
41d25ad0 710 (raise-frame (window-frame ediff-window-B)))
475f9031 711 (if (window-live-p ediff-window-C)
41d25ad0
KH
712 (raise-frame (window-frame ediff-window-C)))))
713 (if (and (ediff-window-display-p)
714 (frame-live-p ediff-control-frame)
475f9031 715 (not (ediff-frame-iconified-p ediff-control-frame)))
41d25ad0 716 (raise-frame ediff-control-frame))
475f9031
KH
717
718 ;; Redisplay whatever buffers are showing, if there is a selected difference
719 (let* ((control-frame ediff-control-frame)
720 (control-buf ediff-control-buffer))
721 (if (and (ediff-buffer-live-p ediff-buffer-A)
722 (ediff-buffer-live-p ediff-buffer-B)
723 (or (not ediff-3way-job)
724 (ediff-buffer-live-p ediff-buffer-C))
725 (ediff-valid-difference-p))
726 (progn
727 (or no-rehighlight
41d25ad0 728 (ediff-select-difference ediff-current-difference))
475f9031
KH
729
730 (ediff-recenter-one-window 'A)
731 (ediff-recenter-one-window 'B)
732 (if ediff-3way-job
733 (ediff-recenter-one-window 'C))
734
735 (if (and (ediff-multiframe-setup-p)
736 (not (ediff-frame-iconified-p ediff-control-frame)))
737 (progn
41d25ad0 738 (ediff-reset-mouse control-frame)
475f9031 739 (or ediff-xemacs-p
41d25ad0 740 (cond ((eq (ediff-device-type) 'ns)
475f9031
KH
741 (unfocus-frame (selected-frame)))
742 (t (unfocus-frame))))
743 ))
744 ))
745 (ediff-eval-in-buffer control-buf
746 (ediff-refresh-mode-lines))
747 ))
748
749;; this function returns to the window it was called from
750;; (which was the control window)
751(defun ediff-recenter-one-window (buf-type)
752 (let* (;; context must be saved before switching to windows A/B/C
753 (ctl-wind (selected-window))
754 (shift (ediff-overlay-start
755 (ediff-get-value-according-to-buffer-type
756 buf-type ediff-narrow-bounds)))
757 (job-name ediff-job-name)
758 (control-buf ediff-control-buffer)
475f9031
KH
759 (window-name (intern (format "ediff-window-%S" buf-type)))
760 (window (if (window-live-p (symbol-value window-name))
761 (symbol-value window-name))))
762
41d25ad0
KH
763 (if (and window ediff-windows-job)
764 (set-window-start window shift))
475f9031
KH
765 (if window
766 (progn
767 (select-window window)
768 (ediff-deactivate-mark)
769 (ediff-position-region
41d25ad0
KH
770 (ediff-get-diff-posn buf-type 'beg nil control-buf)
771 (ediff-get-diff-posn buf-type 'end nil control-buf)
475f9031
KH
772 (ediff-get-diff-posn buf-type 'beg nil control-buf)
773 job-name
774 )))
775 (select-window ctl-wind)
776 ))
777
778
779;; This will have to be refined for 3way jobs
780(defun ediff-toggle-split ()
781 "Toggle vertical/horizontal window split.
782Does nothing if file-A and file-B are in different frames."
783 (interactive)
784 (let* ((wind-A (if (window-live-p ediff-window-A) ediff-window-A))
785 (wind-B (if (window-live-p ediff-window-B) ediff-window-B))
786 (wind-C (if (window-live-p ediff-window-C) ediff-window-C))
41d25ad0
KH
787 (frame-A (if wind-A (window-frame wind-A)))
788 (frame-B (if wind-B (window-frame wind-B)))
789 (frame-C (if wind-C (window-frame wind-C))))
475f9031 790 (if (or (eq frame-A frame-B)
41d25ad0
KH
791 (not (frame-live-p frame-A))
792 (not (frame-live-p frame-B))
475f9031 793 (if ediff-3way-comparison-job
41d25ad0 794 (or (not (frame-live-p frame-C))
475f9031
KH
795 (eq frame-A frame-C) (eq frame-B frame-C))))
796 (setq ediff-split-window-function
797 (if (eq ediff-split-window-function 'split-window-vertically)
798 'split-window-horizontally
799 'split-window-vertically))
800 (message "Buffers being compared are in different frames"))
801 (ediff-recenter 'no-rehighlight)))
802
803(defun ediff-toggle-hilit ()
804 "Switch between highlighting using ASCII flags and highlighting using faces.
805On a dumb terminal, switches between ASCII highlighting and no highlighting."
806 (interactive)
41d25ad0 807 (if (not (ediff-window-display-p))
475f9031
KH
808 (if (eq ediff-highlighting-style 'ascii)
809 (progn
810 (message "ASCII highlighting flags removed")
811 (ediff-unselect-and-select-difference ediff-current-difference
812 'unselect-only)
813 (setq ediff-highlighting-style 'off))
814 (ediff-unselect-and-select-difference ediff-current-difference
815 'select-only))
816 (ediff-unselect-and-select-difference ediff-current-difference
817 'unselect-only)
818 ;; cycle through highlighting
819 (cond ((and ediff-use-faces ediff-highlight-all-diffs)
820 (message "Unhighlighting unselected difference regions")
821 (setq ediff-highlight-all-diffs nil))
822 (ediff-use-faces
823 (message "Highlighting with ASCII flags")
824 (setq ediff-use-faces nil))
825 (t
826 (message "Re-highlighting all difference regions")
827 (setq ediff-use-faces t
828 ediff-highlight-all-diffs t)))
829
830 (if (and ediff-use-faces ediff-highlight-all-diffs)
831 (if (not (face-differs-from-default-p 'ediff-odd-diff-face-A-var))
832 (progn
833 (copy-face ediff-odd-diff-face-A 'ediff-odd-diff-face-A-var)
834 (copy-face ediff-odd-diff-face-B 'ediff-odd-diff-face-B-var)
835 (copy-face ediff-odd-diff-face-C 'ediff-odd-diff-face-C-var)
836 (copy-face ediff-even-diff-face-A 'ediff-even-diff-face-A-var)
837 (copy-face ediff-even-diff-face-B 'ediff-even-diff-face-B-var)
838 (copy-face ediff-even-diff-face-C 'ediff-even-diff-face-C-var)
839 ))
840 (copy-face 'default 'ediff-odd-diff-face-A-var)
841 (copy-face 'default 'ediff-odd-diff-face-B-var)
842 (copy-face 'default 'ediff-odd-diff-face-C-var)
843 (copy-face 'default 'ediff-even-diff-face-A-var)
844 (copy-face 'default 'ediff-even-diff-face-B-var)
845 (copy-face 'default 'ediff-even-diff-face-C-var))
846
847 (ediff-unselect-and-select-difference
848 ediff-current-difference 'select-only))
475f9031
KH
849 )
850
851(defun ediff-toggle-autorefine ()
852 "Toggle auto-refine mode."
853 (interactive)
854 (if ediff-word-mode
855 (error "No fine differences in this mode"))
856 (cond ((eq ediff-auto-refine 'nix)
857 (setq ediff-auto-refine 'on)
858 (ediff-make-fine-diffs ediff-current-difference 'noforce)
859 (message "Auto-refining is ON"))
860 ((eq ediff-auto-refine 'on)
861 (message "Auto-refining is OFF")
862 (setq ediff-auto-refine 'off))
863 (t ;; nix 'em
864 (ediff-set-fine-diff-properties ediff-current-difference 'default)
865 (message "Refinements are HIDDEN")
866 (setq ediff-auto-refine 'nix))
867 ))
868
869(defun ediff-make-or-kill-fine-diffs (arg)
870 "Compute fine diffs. With negative prefix arg, kill fine diffs.
871In both cases, operates on the currrent difference region."
872 (interactive "P")
873 (cond ((eq arg '-)
874 (ediff-clear-fine-differences ediff-current-difference))
875 ((and (numberp arg) (< arg 0))
876 (ediff-clear-fine-differences ediff-current-difference))
877 (t (ediff-make-fine-diffs))))
878
879
880(defun ediff-toggle-help ()
881 "Toggle short/long help message."
882 (interactive)
883 (let (buffer-read-only)
884 (erase-buffer)
885 (setq ediff-prefer-long-help-message (not ediff-prefer-long-help-message))
886 (ediff-set-help-message))
887 ;; remember the icon status of the control frame when the user requested
888 ;; full control message
889 (if (and ediff-prefer-long-help-message (ediff-multiframe-setup-p))
890 (setq ediff-prefer-iconified-control-frame
891 (ediff-frame-iconified-p ediff-control-frame)))
892
893 (setq ediff-window-config-saved "") ; force redisplay
894 (ediff-recenter 'no-rehighlight))
895
896
41d25ad0
KH
897;; If BUF, this is the buffer to toggle, not current buffer.
898(defun ediff-toggle-read-only (&optional buf)
899 "Toggle read-only in current buffer.
900If buffer is under version control and locked, check it out first.
901If optional argument BUF is specified, toggle read-only in that buffer instead
902of the current buffer."
475f9031 903 (interactive)
41d25ad0
KH
904 (let ((ctl-buf (if (null buf) (current-buffer))))
905 (or buf (ediff-recenter))
906 (or buf
907 (setq buf
908 (ediff-get-buffer (ediff-char-to-buftype last-command-char))))
909
910 (ediff-eval-in-buffer buf ; eval in buf A/B/C
911 (let* ((file (buffer-file-name buf))
912 (file-writable (and file
913 (file-exists-p file)
914 (file-writable-p file)))
915 (toggle-ro-cmd (cond (ediff-toggle-read-only-function)
916 ((ediff-file-checked-out-p file)
917 'toggle-read-only)
918 (file-writable 'toggle-read-only)
919 (t (key-binding "\C-x\C-q")))))
920 ;; If the file is checked in, make sure we don't make buffer modifiable
921 ;; without warning the user. The user can fool our checks by making the
922 ;; buffer non-RO without checking the file out. We regard this as a
923 ;; user problem.
924 (if (and (ediff-file-checked-in-p file)
925 ;; If ctl-buf is null, this means we called this
926 ;; non-interactively, in which case don't ask questions
927 ctl-buf)
928 (cond ((not buffer-read-only)
929 (setq toggle-ro-cmd 'toggle-read-only))
930 ((and (or (beep 1) t) ; always beep
931 (y-or-n-p
932 (format
933 "File %s is under version control. Check it out? "
934 (abbreviate-file-name file))))
935 ;; if we checked the file out, we should also change the
936 ;; original state of buffer-read-only to nil. If we don't
937 ;; do this, the mode line will show %%, since the file was
938 ;; RO before ediff started, so the user will think the file
939 ;; is checked in.
940 (ediff-eval-in-buffer ctl-buf
941 (ediff-change-saved-variable
942 'buffer-read-only nil
943 (ediff-char-to-buftype last-command-char))))
944 (t
945 (setq toggle-ro-cmd 'toggle-read-only)
946 (beep 1) (beep 1)
947 (message
948 "Boy, this is risky! Better don't change this file...")
949 (sit-for 3))))
950 (if (and toggle-ro-cmd
951 (string-match "toggle-read-only" (symbol-name toggle-ro-cmd)))
952 (save-excursion
953 (save-window-excursion
954 (command-execute toggle-ro-cmd)))
955 (error "Don't know how to toggle read-only in buffer %S" buf))
956
957 ;; Check if we made the current buffer updatable, but its file is RO.
958 ;; Signal a warning in this case.
959 (if (and file (not buffer-read-only)
960 (eq this-command 'ediff-toggle-read-only)
961 (file-exists-p file)
962 (not (file-writable-p file)))
963 (message "Warning: file %s is read-only"
964 (abbreviate-file-name file) (beep 1)))
965 ))))
475f9031 966
41d25ad0
KH
967
968;; This is a simple-minded check for whether a file is under version control
969;; and is checked out.
970;; If file,v exists but file doesn't, this file is considered to be not checked
971;; in and not checked out for the purpose of patching (since patch won't be
972;; able to read such a file anyway).
973;; FILE is a string representing file name
974(defsubst ediff-file-checked-out-p (file)
975 (and (stringp file)
976 (file-exists-p file)
977 (file-writable-p file)
978 (file-exists-p (concat file ",v"))))
979(defsubst ediff-file-checked-in-p (file)
980 (and (stringp file)
981 (file-exists-p file)
982 (not (file-writable-p file))
983 (file-exists-p (concat file ",v"))))
475f9031
KH
984
985(defun ediff-swap-buffers ()
986 "Rotate the display of buffers A, B, and C."
987 (interactive)
988 (if (and (window-live-p ediff-window-A) (window-live-p ediff-window-B))
989 (let ((buf ediff-buffer-A)
41d25ad0 990 (values ediff-buffer-values-orig-A)
475f9031
KH
991 (diff-vec ediff-difference-vector-A)
992 (hide-regexp ediff-regexp-hide-A)
993 (focus-regexp ediff-regexp-focus-A)
994 (wide-visibility-p (eq ediff-visible-bounds ediff-wide-bounds))
41d25ad0
KH
995 (overlay (if (ediff-window-display-p)
996 ediff-current-diff-overlay-A)))
475f9031
KH
997 (if ediff-3way-comparison-job
998 (progn
999 (set-window-buffer ediff-window-A ediff-buffer-C)
1000 (set-window-buffer ediff-window-B ediff-buffer-A)
1001 (set-window-buffer ediff-window-C ediff-buffer-B)
1002 )
1003 (set-window-buffer ediff-window-A ediff-buffer-B)
1004 (set-window-buffer ediff-window-B ediff-buffer-A))
1005 ;; swap diff buffers
1006 (if ediff-3way-comparison-job
1007 (setq ediff-buffer-A ediff-buffer-C
1008 ediff-buffer-C ediff-buffer-B
1009 ediff-buffer-B buf)
1010 (setq ediff-buffer-A ediff-buffer-B
1011 ediff-buffer-B buf))
1012
1013 ;; swap saved buffer characteristics
1014 (if ediff-3way-comparison-job
41d25ad0
KH
1015 (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-C
1016 ediff-buffer-values-orig-C ediff-buffer-values-orig-B
1017 ediff-buffer-values-orig-B values)
1018 (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-B
1019 ediff-buffer-values-orig-B values))
475f9031
KH
1020
1021 ;; swap diff vectors
1022 (if ediff-3way-comparison-job
1023 (setq ediff-difference-vector-A ediff-difference-vector-C
1024 ediff-difference-vector-C ediff-difference-vector-B
1025 ediff-difference-vector-B diff-vec)
1026 (setq ediff-difference-vector-A ediff-difference-vector-B
1027 ediff-difference-vector-B diff-vec))
1028
1029 ;; swap hide/focus regexp
1030 (if ediff-3way-comparison-job
1031 (setq ediff-regexp-hide-A ediff-regexp-hide-C
1032 ediff-regexp-hide-C ediff-regexp-hide-B
1033 ediff-regexp-hide-B hide-regexp
1034 ediff-regexp-focus-A ediff-regexp-focus-C
1035 ediff-regexp-focus-C ediff-regexp-focus-B
1036 ediff-regexp-focus-B focus-regexp)
1037 (setq ediff-regexp-hide-A ediff-regexp-hide-B
1038 ediff-regexp-hide-B hide-regexp
1039 ediff-regexp-focus-A ediff-regexp-focus-B
1040 ediff-regexp-focus-B focus-regexp))
1041
1042 ;; The following is needed for XEmacs, since there one can't move
1043 ;; overlay to another buffer. In Emacs, this swap is redundant.
41d25ad0 1044 (if (ediff-window-display-p)
475f9031
KH
1045 (if ediff-3way-comparison-job
1046 (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-C
1047 ediff-current-diff-overlay-C ediff-current-diff-overlay-B
1048 ediff-current-diff-overlay-B overlay)
1049 (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-B
1050 ediff-current-diff-overlay-B overlay)))
1051
1052 ;; swap wide bounds
1053 (setq ediff-wide-bounds
1054 (cond (ediff-3way-comparison-job
1055 (list (nth 2 ediff-wide-bounds)
1056 (nth 0 ediff-wide-bounds)
1057 (nth 1 ediff-wide-bounds)))
1058 (ediff-3way-job
1059 (list (nth 1 ediff-wide-bounds)
1060 (nth 0 ediff-wide-bounds)
1061 (nth 2 ediff-wide-bounds)))
1062 (t
1063 (list (nth 1 ediff-wide-bounds)
1064 (nth 0 ediff-wide-bounds)))))
1065 ;; swap narrow bounds
1066 (setq ediff-narrow-bounds
1067 (cond (ediff-3way-comparison-job
1068 (list (nth 2 ediff-narrow-bounds)
1069 (nth 0 ediff-narrow-bounds)
1070 (nth 1 ediff-narrow-bounds)))
1071 (ediff-3way-job
1072 (list (nth 1 ediff-narrow-bounds)
1073 (nth 0 ediff-narrow-bounds)
1074 (nth 2 ediff-narrow-bounds)))
1075 (t
1076 (list (nth 1 ediff-narrow-bounds)
1077 (nth 0 ediff-narrow-bounds)))))
1078 (if wide-visibility-p
1079 (setq ediff-visible-bounds ediff-wide-bounds)
1080 (setq ediff-visible-bounds ediff-narrow-bounds))
1081 ))
1082 (if ediff-3way-job
1083 (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer))
1084 (ediff-recenter 'no-rehighlight)
1085 )
1086
1087
1088(defun ediff-toggle-wide-display ()
1089 "Toggle wide/regular display.
1090This is especially useful when comparing buffers side-by-side."
1091 (interactive)
41d25ad0
KH
1092 (or (ediff-window-display-p)
1093 (error "%sEmacs is not running as a window application"
1094 (if ediff-emacs-p "" "X")))
475f9031
KH
1095 (ediff-recenter 'no-rehighlight) ; make sure buffs are displayed in windows
1096 (let ((ctl-buf ediff-control-buffer))
1097 (setq ediff-wide-display-p (not ediff-wide-display-p))
1098 (if (not ediff-wide-display-p)
1099 (ediff-eval-in-buffer ctl-buf
41d25ad0 1100 (modify-frame-parameters
475f9031
KH
1101 ediff-wide-display-frame ediff-wide-display-orig-parameters)
1102 (sit-for (if ediff-xemacs-p 0.4 0))
1103 ;; restore control buf, since ctl window may have been deleted
1104 ;; during resizing
1105 (set-buffer ctl-buf)
1106 (setq ediff-wide-display-orig-parameters nil
1107 ediff-window-B nil) ; force update of window config
1108 (ediff-recenter 'no-rehighlight))
1109 (funcall ediff-make-wide-display-function)
1110 (sit-for (if ediff-xemacs-p 0.4 0))
1111 (ediff-eval-in-buffer ctl-buf
1112 (setq ediff-window-B nil) ; force update of window config
1113 (ediff-recenter 'no-rehighlight)))))
1114
1115(defun ediff-toggle-multiframe ()
1116 "Switch from the multiframe display to single-frame display and back.
1117This is primarily for debugging, but one can use it for fun, too."
1118 (interactive)
41d25ad0
KH
1119 (or (ediff-window-display-p)
1120 (error "%sEmacs is not running as a window application"
1121 (if ediff-emacs-p "" "X")))
475f9031
KH
1122 (cond ((eq ediff-window-setup-function 'ediff-setup-windows-multiframe)
1123 (setq ediff-window-setup-function 'ediff-setup-windows-plain))
1124 ((eq ediff-window-setup-function 'ediff-setup-windows-plain)
1125 (setq ediff-window-setup-function 'ediff-setup-windows-multiframe)))
1126 (setq ediff-window-B nil)
1127 (ediff-recenter 'no-rehighlight))
1128
1129;; Merging
1130
1131(defun ediff-toggle-show-clashes-only ()
1132 "Toggle the mode where only the regions where both buffers differ with the ancestor are shown."
1133 (interactive)
1134 (if (not ediff-merge-with-ancestor-job)
1135 (error "This command makes sense only when merging with an ancestor"))
1136 (setq ediff-show-clashes-only (not ediff-show-clashes-only))
1137 (if ediff-show-clashes-only
1138 (message "Focus on regions where both buffers differ from the ancestor")
1139 (message "Canceling focus on regions where changes clash")))
1140
1141;; Widening/narrowing
1142
1143(defun ediff-toggle-narrow-region ()
1144 "Toggle narrowing in buffers A, B, and C.
1145Used in ediff-windows/regions only."
1146 (interactive)
1147 (if (eq ediff-buffer-A ediff-buffer-B)
1148 (error
1149 "Buffers A and B are the same. Can't narrow to two different regions"))
1150 (if (eq ediff-visible-bounds ediff-wide-bounds)
1151 (setq ediff-visible-bounds ediff-narrow-bounds)
1152 (setq ediff-visible-bounds ediff-wide-bounds))
1153 (ediff-recenter 'no-rehighlight))
1154
1155;; Narrow bufs A/B/C to ediff-visible-bounds. If this is currently set to
1156;; ediff-wide-bounds, then this actually widens.
41d25ad0
KH
1157;; This function does nothing if job-name is not
1158;; ediff-regions-wordwise/linewise or ediff-windows-wordwise/linewise.
475f9031
KH
1159;; Does nothing if buffer-A = buffer-B since we can't narrow
1160;; to two different regions in one buffer.
1161(defun ediff-visible-region ()
1162 (if (or (eq ediff-buffer-A ediff-buffer-B)
1163 (eq ediff-buffer-A ediff-buffer-C)
1164 (eq ediff-buffer-C ediff-buffer-B))
1165 ()
1166 ;; If ediff-*-regions/windows, ediff-visible-bounds is already set
1167 ;; Otherwise, always use full range.
41d25ad0 1168 (if (not ediff-narrow-job)
475f9031
KH
1169 (setq ediff-visible-bounds ediff-wide-bounds))
1170 (let ((overl-A (ediff-get-value-according-to-buffer-type
1171 'A ediff-visible-bounds))
1172 (overl-B (ediff-get-value-according-to-buffer-type
1173 'B ediff-visible-bounds))
1174 (overl-C (ediff-get-value-according-to-buffer-type
1175 'C ediff-visible-bounds))
1176 )
1177 (ediff-eval-in-buffer ediff-buffer-A
1178 (narrow-to-region
1179 (ediff-overlay-start overl-A) (ediff-overlay-end overl-A)))
1180 (ediff-eval-in-buffer ediff-buffer-B
1181 (narrow-to-region
1182 (ediff-overlay-start overl-B) (ediff-overlay-end overl-B)))
1183
1184 (if ediff-3way-job
1185 (ediff-eval-in-buffer ediff-buffer-C
1186 (narrow-to-region
1187 (ediff-overlay-start overl-C) (ediff-overlay-end overl-C))))
1188 )))
1189
1190
1191;; Window scrolling operations
1192
1193;; Performs some operation on the two file windows (if they are showing).
1194;; Traps all errors on the operation in windows A/B/C.
1195;; Usually, errors come from scrolling off the
1196;; beginning or end of the buffer, and this gives error messages.
1197(defun ediff-operate-on-windows (operation arg)
1198
1199 ;; make sure windows aren't dead
1200 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1201 (ediff-recenter 'no-rehighlight))
1202 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1203 (ediff-buffer-live-p ediff-buffer-B)
1204 (or (not ediff-3way-job) ediff-buffer-C)
1205 ))
1206 (error "You've killed an essential Ediff buffer---Please quit Ediff"))
1207
1208 (let* ((wind (selected-window))
1209 (wind-A ediff-window-A)
1210 (wind-B ediff-window-B)
1211 (wind-C ediff-window-C)
1212 (three-way ediff-3way-job))
1213
1214 (select-window wind-A)
1215 (condition-case nil
1216 (funcall operation arg)
1217 (error))
1218 (select-window wind-B)
1219 (condition-case nil
1220 (funcall operation arg)
1221 (error))
1222 (if three-way
1223 (progn
1224 (select-window wind-C)
1225 (condition-case nil
1226 (funcall operation arg)
1227 (error))))
1228
1229 (select-window wind)))
1230
1231(defun ediff-scroll-vertically (&optional arg)
1232 "Vertically scroll buffers A, B \(and C if appropriate\).
1233With optional argument ARG, scroll ARG lines; otherwise scroll by nearly
1234the height of window-A."
1235 (interactive "P")
1236
1237 ;; make sure windows aren't dead
1238 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1239 (ediff-recenter 'no-rehighlight))
1240 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1241 (ediff-buffer-live-p ediff-buffer-B)
1242 (or (not ediff-3way-job)
1243 (ediff-buffer-live-p ediff-buffer-C))
1244 ))
1245 (error "You've killed an essential Ediff buffer---Please quit Ediff"))
1246
1247 (ediff-operate-on-windows
1248 (if (memq last-command-char '(?v ?\C-v))
1249 'scroll-up
1250 'scroll-down)
1251 ;; calculate argument to scroll-up/down
1252 ;; if there is an explicit argument
1253 (if (and arg (not (equal arg '-)))
1254 ;; use it
1255 (prefix-numeric-value arg)
1256 ;; if not, see if we can determine a default amount (the window height)
1257 (let* (default-amount)
1258 (setq default-amount
1259 (- (min (window-height ediff-window-A)
1260 (window-height ediff-window-B)
1261 (if ediff-3way-job
1262 (window-height ediff-window-C)
1263 123) ; some large number
1264 )
1265 1 next-screen-context-lines))
1266 ;; window found
1267 (if arg
1268 ;; C-u as argument means half of default amount
1269 (/ default-amount 2)
1270 ;; no argument means default amount
1271 default-amount)))))
1272
1273
1274(defun ediff-scroll-horizontally (&optional arg)
1275 "Horizontally scroll buffers A, B \(and C if appropriate\).
1276If an argument is given, that is how many columns are scrolled, else nearly
1277the width of the A/B/C windows."
1278 (interactive "P")
1279
1280 ;; make sure windows aren't dead
1281 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1282 (ediff-recenter 'no-rehighlight))
1283 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1284 (ediff-buffer-live-p ediff-buffer-B)
1285 (or (not ediff-3way-job)
1286 (ediff-buffer-live-p ediff-buffer-C))
1287 ))
1288 (error "You've killed an essential Ediff buffer---Please quit Ediff"))
1289
1290 (ediff-operate-on-windows
1291 (if (= last-command-char ?<)
1292 'scroll-left
1293 'scroll-right)
1294 ;; calculate argument to scroll-left/right
1295 ;; if there is an explicit argument
1296 (if (and arg (not (equal arg '-)))
1297 ;; use it
1298 (prefix-numeric-value arg)
1299 ;; if not, see if we can determine a default amount
1300 ;; (half the window width)
1301 (if (null ediff-control-window)
1302 ;; no control window, use nil
1303 nil
1304 (let ((default-amount
1305 (- (/ (min (window-width ediff-window-A)
1306 (window-width ediff-window-B)
1307 (if ediff-3way-comparison-job
1308 (window-width ediff-window-C)
1309 500) ; some large number
1310 )
1311 2)
1312 3)))
1313 ;; window found
1314 (if arg
1315 ;; C-u as argument means half of default amount
1316 (/ default-amount 2)
1317 ;; no argument means default amount
1318 default-amount))))))
1319
1320
1321;;BEG, END show the region to be positioned.
1322;;JOB-NAME holds ediff-job-name. Ediff-windows job positions regions
1323;;differently.
1324(defun ediff-position-region (beg end pos job-name)
1325 (if (> end (point-max))
1326 (setq end (point-max)))
41d25ad0 1327 (if ediff-windows-job
475f9031
KH
1328 (if (pos-visible-in-window-p end)
1329 () ; do nothing, wind is already positioned
1330 ;; at this point, windows are positioned at the beginning of the
1331 ;; file regions (not diff-regions) being compared.
1332 (save-excursion
1333 (move-to-window-line (- (window-height) 2))
1334 (let ((amount (+ 2 (count-lines (point) end))))
1335 (scroll-up amount))))
1336 (set-window-start (selected-window) beg)
1337 (if (pos-visible-in-window-p end)
1338 ;; Determine the number of lines that the region occupies
41d25ad0
KH
1339 (let ((lines 0)
1340 (prev-point 0))
1341 (while ( and (> end (progn
1342 (move-to-window-line lines)
1343 (point)))
1344 ;; `end' may be beyond the window bottom, so check
1345 ;; that we are making progres
1346 (< prev-point (point)))
1347 (setq prev-point (point))
475f9031
KH
1348 (setq lines (1+ lines)))
1349 ;; And position the beginning on the right line
1350 (goto-char beg)
1351 (recenter (/ (1+ (max (- (1- (window-height (selected-window)))
1352 lines)
1353 1)
1354 )
1355 2))))
1356 (goto-char pos)
1357 ))
1358
1359
1360(defun ediff-next-difference (&optional arg)
1361 "Advance to the next difference.
1362With a prefix argument, go back that many differences."
1363 (interactive "P")
1364 (if (< ediff-current-difference ediff-number-of-differences)
1365 (let ((n (min ediff-number-of-differences
1366 (+ ediff-current-difference (if arg arg 1))))
41d25ad0 1367 regexp-skip)
475f9031
KH
1368
1369 (or (>= n ediff-number-of-differences)
1370 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
1371 (ediff-install-fine-diff-if-necessary n))
1372 (while (and (< n ediff-number-of-differences)
1373 (or
1374 ;; regexp skip
1375 regexp-skip
1376 ;; skip clashes, if necessary
1377 (and ediff-show-clashes-only
1378 (string-match "prefer"
1379 (or (ediff-get-state-of-merge n) "")))
1380 ;; skip difference regions that differ in white space
1381 (and ediff-ignore-similar-regions
1382 (ediff-no-fine-diffs-p n))))
1383 (setq n (1+ n))
1384 (if (= 0 (mod n 20))
1385 (message "Skipped over region %d and counting ..." n))
1386 (or (>= n ediff-number-of-differences)
1387 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
1388 (ediff-install-fine-diff-if-necessary n))
1389 )
41d25ad0 1390 (message "")
475f9031
KH
1391 (ediff-unselect-and-select-difference n)
1392 ) ; let
1393 (ediff-visible-region)
1394 (error "At end of the difference list")))
1395
1396(defun ediff-previous-difference (&optional arg)
1397 "Go to the previous difference.
1398With a prefix argument, go back that many differences."
1399 (interactive "P")
1400 (if (> ediff-current-difference -1)
1401 (let ((n (max -1 (- ediff-current-difference (if arg arg 1))))
41d25ad0 1402 regexp-skip)
475f9031
KH
1403
1404 (or (< n 0)
1405 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
1406 (ediff-install-fine-diff-if-necessary n))
1407 (while (and (> n -1)
1408 (or
1409 ;; regexp skip
1410 regexp-skip
1411 ;; skip clashes, if necessary
1412 (and ediff-show-clashes-only
1413 (string-match "prefer"
1414 (or (ediff-get-state-of-merge n) "")))
1415 ;; skip difference regions that differ in white space
1416 (and ediff-ignore-similar-regions
1417 (ediff-no-fine-diffs-p n))))
1418 (if (= 0 (mod (1+ n) 20))
1419 (message "Skipped over region %d and counting ..." (1+ n)))
1420 (setq n (1- n))
1421 (or (< n 0)
1422 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
1423 (ediff-install-fine-diff-if-necessary n))
1424 )
41d25ad0 1425 (message "")
475f9031
KH
1426 (ediff-unselect-and-select-difference n)
1427 ) ; let
1428 (ediff-visible-region)
1429 (error "At beginning of the difference list")))
1430
1431(defun ediff-jump-to-difference (difference-number)
1432 "Go to the difference specified as a prefix argument."
1433 (interactive "p")
41d25ad0
KH
1434 (setq difference-number (1- difference-number))
1435 (if (and (>= difference-number -1)
1436 (< difference-number (1+ ediff-number-of-differences)))
1437 (ediff-unselect-and-select-difference difference-number)
1438 (error "Bad difference number, %d" difference-number)))
475f9031
KH
1439
1440(defun ediff-jump-to-difference-at-point ()
1441 "Go to difference closest to the point in buffer A, B, or C.
1442The type of buffer depends on last command character \(a, b, or c\) that
1443invoked this command."
1444 (interactive)
41d25ad0 1445 (let ((buf-type (ediff-char-to-buftype last-command-char)))
475f9031
KH
1446 (ediff-jump-to-difference (ediff-diff-at-point buf-type))))
1447
1448
1449;; find region most related to the current point position (or POS, if given)
1450(defun ediff-diff-at-point (buf-type &optional pos)
1451 (let ((buffer (ediff-get-buffer buf-type))
1452 (ctl-buffer ediff-control-buffer)
1453 (max-dif-num (1- ediff-number-of-differences))
1454 (diff-no -1)
1455 (prev-beg 0)
1456 (prev-end 0)
1457 (beg 0)
1458 (end 0))
1459
1460 (ediff-eval-in-buffer buffer
1461 (setq pos (or pos (point)))
1462 (while (and (or (< pos prev-beg) (> pos beg))
1463 (< diff-no max-dif-num))
1464 (setq diff-no (1+ diff-no))
1465 (setq prev-beg beg
1466 prev-end end)
1467 (setq beg (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer)
1468 end (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer))
1469 )
1470
1471 (if (< (abs (- pos prev-end))
1472 (abs (- pos beg)))
1473 diff-no
1474 (1+ diff-no)) ; jump-to-diff works with diff nums higher by 1
1475 )))
1476
1477\f
1478;;; Copying diffs.
1479
1480(defun ediff-diff-to-diff (arg &optional keys)
1481 "Copy buffer-X'th diff to buffer Y \(X,Y are A, B, or C\).
1482If numerical prefix argument, copy this diff specified in the arg.
1483Otherwise, copy the difference given by `ediff-current-difference'.
1484This command assumes it is bound to a 2-character key sequence, `ab', `ba',
1485`ac', etc., which is used to determine the types of buffers to be used for
1486copying difference regions. The first character in the sequence specifies
1487the source buffer and the second specifies the target.
1488
1489If the second optional argument, a 2-character string, is given, use it to
1490determine the source and the target buffers instead of the command keys."
1491 (interactive "P")
1492 (or keys (setq keys (this-command-keys)))
1493 (if arg
1494 (ediff-jump-to-difference arg))
1495 (let* ((key1 (aref keys 0))
1496 (key2 (aref keys 1))
1497 (char1 (if (and ediff-xemacs-p (eventp key1)) (event-key key1) key1))
1498 (char2 (if (and ediff-xemacs-p (eventp key1)) (event-key key2) key2)))
1499 (ediff-copy-diff ediff-current-difference
1500 (ediff-char-to-buftype char1)
1501 (ediff-char-to-buftype char2))
1502 (ediff-recenter 'no-rehighlight)))
1503
1504
1505;; Copy diff N from FROM-BUF-TYPE \(given as A, B or C\) to TO-BUF-TYPE.
1506;; If optional DO-NOT-SAVE is non-nil, do not save the old value of the
1507;; target diff. This is used in merging, when constructing the merged
1508;; version.
1509(defun ediff-copy-diff (n from-buf-type to-buf-type
1510 &optional batch-invocation reg-to-copy)
1511 (let* ((to-buf (ediff-get-buffer to-buf-type))
1512 ;;(from-buf (if (not reg-to-copy) (ediff-get-buffer from-buf-type)))
1513 (ctrl-buf ediff-control-buffer)
1514 (saved-p t)
1515 (three-way ediff-3way-job)
1516 messg
1517 ediff-verbose-p
1518 reg-to-delete reg-to-delete-beg reg-to-delete-end)
1519
475f9031
KH
1520 (setq reg-to-delete-beg
1521 (ediff-get-diff-posn to-buf-type 'beg n ctrl-buf))
1522 (setq reg-to-delete-end
1523 (ediff-get-diff-posn to-buf-type 'end n ctrl-buf))
1524
1525 (if reg-to-copy
1526 (setq from-buf-type nil)
1527 (setq reg-to-copy (ediff-get-region-contents n from-buf-type ctrl-buf)))
1528
1529 (setq reg-to-delete (ediff-get-region-contents
1530 n to-buf-type ctrl-buf
1531 reg-to-delete-beg reg-to-delete-end))
1532
1533 (setq ediff-disturbed-overlays nil) ; clear before use
1534
1535 (if (string= reg-to-delete reg-to-copy)
1536 (setq saved-p nil) ; refuse to copy identical buffers
475f9031
KH
1537 ;; seems ok to copy
1538 (if (or batch-invocation (ediff-test-save-region n to-buf-type))
1539 (condition-case conds
1540 (progn
1541 (ediff-eval-in-buffer to-buf
1542 ;; to prevent flags from interfering if buffer is writable
41d25ad0 1543 (let ((inhibit-read-only (null buffer-read-only)))
475f9031
KH
1544 ;; these two insert a dummy char to overcome a bug in
1545 ;; XEmacs, which sometimes prevents 0-length extents
1546 ;; from sensing insertion at its end-points.
1547 (if ediff-xemacs-p
1548 (progn
1549 (goto-char reg-to-delete-end)
1550 (insert-before-markers "@")))
1551
1552 (goto-char reg-to-delete-end)
1553 (insert-before-markers reg-to-copy)
1554
1555 ;; delete the dummy char "@"
1556 (if ediff-xemacs-p
1557 (delete-char 1))
1558
1559 (if ediff-xemacs-p
41d25ad0
KH
1560 (if (> reg-to-delete-end reg-to-delete-beg)
1561 (kill-region reg-to-delete-beg
1562 reg-to-delete-end))
475f9031
KH
1563 (if (> reg-to-delete-end reg-to-delete-beg)
1564 (kill-region reg-to-delete-beg reg-to-delete-end)
1565 (ediff-move-disturbed-overlays reg-to-delete-beg)
1566 ))
1567 ))
1568 (or batch-invocation
1569 (setq
1570 messg
1571 (ediff-save-diff-region n to-buf-type reg-to-delete))))
1572 (error (message "ediff-copy-diff: %s %s"
1573 (car conds)
1574 (mapconcat 'prin1-to-string (cdr conds) " "))
1575 (beep 1)
1576 (sit-for 2)
1577 (setq saved-p nil)
1578 )))
1579 )
1580
1581 ;; adjust state of difference in case 3-way and diff was copied ok
1582 (if (and saved-p three-way)
41d25ad0 1583 (ediff-set-state-of-diff-in-all-buffers n ctrl-buf))
475f9031
KH
1584
1585 (if batch-invocation
1586 (ediff-clear-fine-differences n)
1587 ;; If diff3 job, we should recompute fine diffs so we clear them
1588 ;; before reinserting flags (and thus before ediff-recenter).
1589 (if (and saved-p three-way)
1590 (ediff-clear-fine-differences n))
41d25ad0
KH
1591
1592 (ediff-refresh-mode-lines)
1593
475f9031
KH
1594 ;; For diff2 jobs, don't recompute fine diffs, since we know there
1595 ;; aren't any. So we clear diffs after ediff-recenter.
1596 (if (and saved-p (not three-way))
1597 (ediff-clear-fine-differences n))
1598 ;; Make sure that the message about saving and how to restore is seen
1599 ;; by the user
1600 (message messg))
1601 ))
1602
1603;; Save Nth diff of buffer BUF-TYPE \(A, B, or C\).
1604;; That is to say, the Nth diff on the `ediff-killed-diffs-alist'. REG
1605;; is the region to save. It is redundant here, but is passed anyway, for
1606;; convenience.
1607(defun ediff-save-diff-region (n buf-type reg)
1608 (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist))
1609 (buf (ediff-get-buffer buf-type))
1610 (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved))))
1611
1612 (if this-buf-n-th-diff-saved
1613 ;; either nothing saved for n-th diff and buffer or we OK'ed
1614 ;; overriding
1615 (setcdr this-buf-n-th-diff-saved reg)
1616 (if n-th-diff-saved ;; n-th diff saved, but for another buffer
1617 (nconc n-th-diff-saved (list (cons buf reg)))
1618 (setq ediff-killed-diffs-alist ;; create record for n-th diff
1619 (cons (list n (cons buf reg))
1620 ediff-killed-diffs-alist))))
1621 (message "Saving old diff region #%d of buffer %S. To recover, type `r%s'"
1622 (1+ n) buf-type
1623 (if ediff-merge-job
1624 "" (downcase (symbol-name buf-type))))
1625 ))
1626
1627;; Test if saving Nth difference region of buffer BUF-TYPE is possible.
1628(defun ediff-test-save-region (n buf-type)
1629 (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist))
1630 (buf (ediff-get-buffer buf-type))
1631 (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved))))
1632
1633 (if this-buf-n-th-diff-saved
1634 (if (yes-or-no-p
1635 (format
1636 "You've previously copied diff region %d to buffer %S. Confirm "
1637 (1+ n) buf-type))
1638 t
1639 (error "Quit"))
1640 t)))
1641
1642(defun ediff-pop-diff (n buf-type)
1643 "Pop last killed Nth diff region from buffer BUF-TYPE."
1644 (let* ((n-th-record (assoc n ediff-killed-diffs-alist))
1645 (buf (ediff-get-buffer buf-type))
1646 (saved-rec (assoc buf (cdr n-th-record)))
1647 (three-way ediff-3way-job)
1648 (ctl-buf ediff-control-buffer)
1649 ediff-verbose-p
1650 saved-diff reg-beg reg-end recovered)
1651
1652 (if (cdr saved-rec)
1653 (setq saved-diff (cdr saved-rec))
1654 (if (> ediff-number-of-differences 0)
1655 (error "Nothing saved for diff %d in buffer %S" (1+ n) buf-type)
1656 (error "No differences found")))
1657
475f9031
KH
1658 (setq reg-beg (ediff-get-diff-posn buf-type 'beg n ediff-control-buffer))
1659 (setq reg-end (ediff-get-diff-posn buf-type 'end n ediff-control-buffer))
1660 (setq ediff-disturbed-overlays nil) ; clear before use
1661
1662 (condition-case conds
1663 (ediff-eval-in-buffer buf
41d25ad0 1664 (let ((inhibit-read-only (null buffer-read-only)))
475f9031
KH
1665 ;; these two insert a dummy char to overcome a bug in XEmacs,
1666 ;; which sometimes prevents 0-length extents from sensing
1667 ;; insertion at its end-points.
1668 (if ediff-xemacs-p
1669 (progn
1670 (goto-char reg-end)
1671 (insert-before-markers "@")))
1672
1673 (goto-char reg-end)
1674 (insert-before-markers saved-diff)
1675
1676 ;; delete dummy char
1677 (if ediff-xemacs-p
1678 (delete-char 1))
1679
1680 (if ediff-xemacs-p
41d25ad0
KH
1681 (if (> reg-end reg-beg)
1682 (kill-region reg-beg reg-end))
475f9031
KH
1683 (if (> reg-end reg-beg)
1684 (kill-region reg-beg reg-end)
1685 (ediff-move-disturbed-overlays reg-beg)
1686 ))
1687
1688 (setq recovered t)
1689 ))
1690 (error (message "ediff-pop-diff: %s %s"
1691 (car conds)
1692 (mapconcat 'prin1-to-string (cdr conds) " "))
1693 (beep 1)))
1694
41d25ad0
KH
1695 ;; Clearing fine diffs is necessary for
1696 ;; ediff-unselect-and-select-difference to properly recompute them. We
1697 ;; can't rely on ediff-copy-diff to clear this vector, as the user might
1698 ;; have modified diff regions after copying and, thus, may have recomputed
1699 ;; fine diffs.
475f9031
KH
1700 (if recovered
1701 (ediff-clear-fine-differences n))
1702
1703 ;; adjust state of difference
1704 (if (and three-way recovered)
1705 (ediff-set-state-of-diff-in-all-buffers n ctl-buf))
1706
41d25ad0
KH
1707 (ediff-refresh-mode-lines)
1708
475f9031
KH
1709 (if recovered
1710 (progn
1711 (setq n-th-record (delq saved-rec n-th-record))
1712 (message "Diff region %d in buffer %S restored" (1+ n) buf-type)
1713 ))
1714 ))
1715
1716(defun ediff-restore-diff (arg &optional key)
1717 "Restore ARGth diff from `ediff-killed-diffs-alist'.
1718ARG is a prefix argument. If ARG is nil, restore current-difference.
1719
1720If the second optional argument, a character, is given, use it to
1721determine the target buffer instead of last-command-char"
1722 (interactive "P")
1723 (if arg
1724 (ediff-jump-to-difference arg))
1725 (ediff-pop-diff ediff-current-difference
1726 (ediff-char-to-buftype (or key last-command-char)))
1727 (ediff-recenter 'no-rehighlight))
1728
1729(defun ediff-toggle-regexp-match ()
1730 "Toggle between focusing and hiding of difference regions that match
1731a regular expression typed in by the user."
1732 (interactive)
1733 (let ((regexp-A "")
1734 (regexp-B "")
1735 (regexp-C "")
1736 msg-connective alt-msg-connective alt-connective)
1737 (cond
1738 ((or (and (eq ediff-skip-diff-region-function
1739 'ediff-focus-on-regexp-matches)
1740 (eq last-command-char ?f))
1741 (and (eq ediff-skip-diff-region-function 'ediff-hide-regexp-matches)
1742 (eq last-command-char ?h)))
1743 (message "Selective browsing by regexp turned off")
1744 (setq ediff-skip-diff-region-function 'ediff-show-all-diffs))
1745 ((eq last-command-char ?h)
1746 (setq ediff-skip-diff-region-function 'ediff-hide-regexp-matches
1747 regexp-A
1748 (read-string
1749 (format
1750 "Ignore A-regions matching this regexp (default \"%s\"): "
1751 ediff-regexp-hide-A))
1752 regexp-B
1753 (read-string
1754 (format
1755 "Ignore B-regions matching this regexp (default \"%s\"): "
1756 ediff-regexp-hide-B)))
1757 (if ediff-3way-comparison-job
1758 (setq regexp-C
1759 (read-string
1760 (format
1761 "Ignore C-regions matching this regexp (default \"%s\"): "
1762 ediff-regexp-hide-C))))
1763 (if (eq ediff-hide-regexp-connective 'and)
1764 (setq msg-connective "BOTH"
1765 alt-msg-connective "ONE OF"
1766 alt-connective 'or)
1767 (setq msg-connective "ONE OF"
1768 alt-msg-connective "BOTH"
1769 alt-connective 'and))
1770 (if (y-or-n-p
1771 (format
1772 "Hiding diff regions that match %s regexps. Use %s instead? "
1773 msg-connective alt-msg-connective))
1774 (progn
1775 (setq ediff-hide-regexp-connective alt-connective)
1776 (message "Hiding diff regions that match %s regexps"
1777 alt-msg-connective))
1778 (message "Hiding diff regions that match %s regexps" msg-connective))
1779 (or (string= regexp-A "") (setq ediff-regexp-hide-A regexp-A))
1780 (or (string= regexp-B "") (setq ediff-regexp-hide-B regexp-B))
1781 (or (string= regexp-C "") (setq ediff-regexp-hide-C regexp-C)))
1782 ((eq last-command-char ?f)
1783 (setq ediff-skip-diff-region-function 'ediff-focus-on-regexp-matches
1784 regexp-A
1785 (read-string
1786 (format
1787 "Focus on A-regions matching this regexp (default \"%s\"): "
1788 ediff-regexp-focus-A))
1789 regexp-B
1790 (read-string
1791 (format
1792 "Focus on B-regions matching this regexp (default \"%s\"): "
1793 ediff-regexp-focus-B)))
1794 (if ediff-3way-comparison-job
1795 (setq regexp-C
1796 (read-string
1797 (format
1798 "Focus on C-regions matching this regexp (default \"%s\"): "
1799 ediff-regexp-focus-C))))
1800 (if (eq ediff-focus-regexp-connective 'and)
1801 (setq msg-connective "BOTH"
1802 alt-msg-connective "ONE OF"
1803 alt-connective 'or)
1804 (setq msg-connective "ONE OF"
1805 alt-msg-connective "BOTH"
1806 alt-connective 'and))
1807 (if (y-or-n-p
1808 (format
1809 "Focusing on diff regions that match %s regexps. Use %s instead? "
1810 msg-connective alt-msg-connective))
1811 (progn
1812 (setq ediff-focus-regexp-connective alt-connective)
1813 (message "Focusing on diff regions that match %s regexps"
1814 alt-msg-connective))
1815 (message "Focusing on diff regions that match %s regexps"
1816 msg-connective))
1817 (or (string= regexp-A "") (setq ediff-regexp-focus-A regexp-A))
1818 (or (string= regexp-B "") (setq ediff-regexp-focus-B regexp-B))
1819 (or (string= regexp-C "") (setq ediff-regexp-focus-C regexp-C))))))
1820
1821(defun ediff-toggle-skip-similar ()
1822 (interactive)
1823 (if (not (eq ediff-auto-refine 'on))
1824 (error
1825 "Can't skip over whitespace regions: first turn auto-refining on"))
1826 (setq ediff-ignore-similar-regions (not ediff-ignore-similar-regions))
1827 (if ediff-ignore-similar-regions
1828 (message
1829 "Skipping regions that differ only in white space & line breaks")
1830 (message "Skipping over white-space differences turned off")))
1831
1832(defun ediff-focus-on-regexp-matches (n)
1833 "Focus on diffs that match regexp `ediff-regexp-focus-A/B'.
1834Regions to be ignored according to this function are those where
1835buf A region doesn't match `ediff-regexp-focus-A' and buf B region
1836doesn't match `ediff-regexp-focus-B'.
1837This function returns nil if the region number N (specified as
1838an argument) is not to be ignored and t if region N is to be ignored.
1839
1840N is a region number used by Ediff internally. It is 1 less
1841the number seen by the user."
1842 (if (ediff-valid-difference-p n)
1843 (let* ((ctl-buf ediff-control-buffer)
1844 (regex-A ediff-regexp-focus-A)
1845 (regex-B ediff-regexp-focus-B)
1846 (regex-C ediff-regexp-focus-C)
1847 (reg-A-match (ediff-eval-in-buffer ediff-buffer-A
1848 (goto-char (ediff-get-diff-posn 'A 'beg n ctl-buf))
1849 (re-search-forward
1850 regex-A
1851 (ediff-get-diff-posn 'A 'end n ctl-buf)
1852 t)))
1853 (reg-B-match (ediff-eval-in-buffer ediff-buffer-B
1854 (goto-char (ediff-get-diff-posn 'B 'beg n ctl-buf))
1855 (re-search-forward
1856 regex-B
1857 (ediff-get-diff-posn 'B 'end n ctl-buf)
1858 t)))
1859 (reg-C-match (if ediff-3way-comparison-job
1860 (ediff-eval-in-buffer ediff-buffer-C
1861 (goto-char
1862 (ediff-get-diff-posn 'C 'beg n ctl-buf))
1863 (re-search-forward
1864 regex-C
1865 (ediff-get-diff-posn 'C 'end n ctl-buf)
1866 t)))))
1867 (not (eval (if ediff-3way-comparison-job
1868 (list ediff-focus-regexp-connective
1869 reg-A-match reg-B-match reg-C-match)
1870 (list ediff-focus-regexp-connective
1871 reg-A-match reg-B-match))))
1872 )))
1873
1874(defun ediff-hide-regexp-matches (n)
1875 "Hide diffs that match regexp `ediff-regexp-hide-A/B/C'.
1876Regions to be ignored are those where buf A region matches
1877`ediff-regexp-hide-A' and buf B region matches `ediff-regexp-hide-B'.
1878This function returns nil if the region number N (specified as
1879an argument) is not to be ignored and t if region N is to be ignored.
1880
1881N is a region number used by Ediff internally. It is 1 less
1882the number seen by the user."
1883 (if (ediff-valid-difference-p n)
1884 (let* ((ctl-buf ediff-control-buffer)
1885 (regex-A ediff-regexp-hide-A)
1886 (regex-B ediff-regexp-hide-B)
1887 (regex-C ediff-regexp-hide-C)
1888 (reg-A-match (ediff-eval-in-buffer ediff-buffer-A
1889 (goto-char (ediff-get-diff-posn 'A 'beg n ctl-buf))
1890 (re-search-forward
1891 regex-A
1892 (ediff-get-diff-posn 'A 'end n ctl-buf)
1893 t)))
1894 (reg-B-match (ediff-eval-in-buffer ediff-buffer-B
1895 (goto-char (ediff-get-diff-posn 'B 'beg n ctl-buf))
1896 (re-search-forward
1897 regex-B
1898 (ediff-get-diff-posn 'B 'end n ctl-buf)
1899 t)))
1900 (reg-C-match (if ediff-3way-comparison-job
1901 (ediff-eval-in-buffer ediff-buffer-C
1902 (goto-char
1903 (ediff-get-diff-posn 'C 'beg n ctl-buf))
1904 (re-search-forward
1905 regex-C
1906 (ediff-get-diff-posn 'C 'end n ctl-buf)
1907 t)))))
1908 (eval (if ediff-3way-comparison-job
1909 (list ediff-hide-regexp-connective
1910 reg-A-match reg-B-match reg-C-match)
1911 (list ediff-hide-regexp-connective reg-A-match reg-B-match)))
1912 )))
1913
1914
1915\f
1916;;; Quitting, suspending, etc.
1917
1918(defun ediff-quit ()
1919 "Finish an Ediff session and exit Ediff.
1920Unselects the selected difference, if any, restores the read-only and modified
1921flags of the compared file buffers, kills Ediff buffers for this session
1922\(but not buffers A, B, C\)."
1923 (interactive)
1924 (if (prog1
1925 (y-or-n-p "Do you really want to exit Ediff? ")
1926 (message ""))
1927 (ediff-really-quit)))
1928
1929
1930;; Perform the quit operations.
1931(defun ediff-really-quit ()
475f9031
KH
1932 (ediff-unhighlight-diffs-totally)
1933 (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also)
1934 (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also)
1935 (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also)
1936
1937 (ediff-delete-temp-files)
1938
1939 ;; Restore visibility range. This affects only ediff-*-regions/windows.
1940 ;; Since for other job names ediff-visible-region sets
1941 ;; ediff-visible-bounds to ediff-wide-bounds, the settings below are
1942 ;; ignored for such jobs.
1943 (if ediff-quit-widened
1944 (setq ediff-visible-bounds ediff-wide-bounds)
1945 (setq ediff-visible-bounds ediff-narrow-bounds))
1946
1947 ;; Apply selective display to narrow or widen
1948 (ediff-visible-region)
1949 (mapcar (function (lambda (overl)
1950 (if (ediff-overlayp overl)
1951 (ediff-delete-overlay overl))))
1952 ediff-wide-bounds)
1953 (mapcar (function (lambda (overl)
1954 (if (ediff-overlayp overl)
1955 (ediff-delete-overlay overl))))
1956 ediff-narrow-bounds)
1957
1958 ;; restore buffer mode line id's in buffer-A/B/C
475f9031
KH
1959 (let ((control-buffer ediff-control-buffer))
1960 (condition-case nil
1961 (ediff-eval-in-buffer ediff-buffer-A
475f9031
KH
1962 (setq ediff-this-buffer-control-sessions
1963 (delq control-buffer ediff-this-buffer-control-sessions))
475f9031
KH
1964 (kill-local-variable 'mode-line-buffer-identification)
1965 (kill-local-variable 'mode-line-format)
1966 )
1967 (error))
1968
1969 (condition-case nil
1970 (ediff-eval-in-buffer ediff-buffer-B
1971 (setq ediff-this-buffer-control-sessions
1972 (delq control-buffer ediff-this-buffer-control-sessions))
475f9031
KH
1973 (kill-local-variable 'mode-line-buffer-identification)
1974 (kill-local-variable 'mode-line-format)
1975 )
1976 (error))
1977
1978 (condition-case nil
1979 (ediff-eval-in-buffer ediff-buffer-C
475f9031
KH
1980 (kill-local-variable 'mode-line-buffer-identification)
1981 (kill-local-variable 'mode-line-format)
1982 )
1983 (error))
1984 )
1985 ;; restore state of buffers to what it was before ediff
1986 (ediff-restore-protected-variables)
41d25ad0
KH
1987 ;; good place to kill buffers A/B/C
1988 (run-hooks 'ediff-cleanup-hooks)
475f9031
KH
1989 (run-hooks 'ediff-quit-hooks))
1990
1991
1992(defun ediff-delete-temp-files ()
1993 (if (stringp ediff-temp-file-A)
1994 (delete-file ediff-temp-file-A))
1995 (if (stringp ediff-temp-file-B)
1996 (delete-file ediff-temp-file-B))
1997 (if (stringp ediff-temp-file-C)
1998 (delete-file ediff-temp-file-C)))
1999
2000
2001;; Kill control buffer, other auxiliary Ediff buffers.
2002;; Leave one of the frames split between buffers A/B/C
2003(defun ediff-cleanup-mess ()
2004 (let ((buff-A ediff-buffer-A)
2005 (buff-B ediff-buffer-B)
2006 (buff-C ediff-buffer-C)
2007 (ctl-buf ediff-control-buffer)
2008 (ctl-frame ediff-control-frame)
2009 (three-way-job ediff-3way-job))
2010
2011 (ediff-kill-buffer-carefully ediff-diff-buffer)
2012 (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
2013 (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
2014 (ediff-kill-buffer-carefully ediff-tmp-buffer)
2015 (ediff-kill-buffer-carefully ediff-error-buffer)
2016 (ediff-kill-buffer-carefully ediff-patch-diagnostics)
2017 (ediff-kill-buffer-carefully ediff-msg-buffer)
2018 (ediff-kill-buffer-carefully ediff-debug-buffer)
2019
41d25ad0
KH
2020 ;;(redraw-display)
2021 (if (and (ediff-window-display-p) (frame-live-p ctl-frame))
2022 (delete-frame ctl-frame))
475f9031
KH
2023 (ediff-kill-buffer-carefully ctl-buf)
2024
2025 (delete-other-windows)
2026
2027 ;; display only if not visible
2028 (condition-case nil
2029 (or (ediff-get-visible-buffer-window buff-B)
2030 (switch-to-buffer buff-B))
2031 (error))
2032 (condition-case nil
2033 (or (ediff-get-visible-buffer-window buff-A)
2034 (progn
2035 (if (ediff-get-visible-buffer-window buff-B)
2036 (split-window-vertically))
2037 (switch-to-buffer buff-A)))
2038 (error))
2039 (if three-way-job
2040 (condition-case nil
2041 (or (ediff-get-visible-buffer-window buff-C)
2042 (progn
2043 (if (or (ediff-get-visible-buffer-window buff-A)
2044 (ediff-get-visible-buffer-window buff-B))
2045 (split-window-vertically))
2046 (switch-to-buffer buff-C)
2047 (balance-windows)))
2048 (error)))
2049 (message "")
2050 ))
41d25ad0
KH
2051
2052(defun ediff-janitor ()
2053 "Kill buffers A, B, and, possibly, C, if these buffers aren't modified.
2054In merge jobs, buffer C is never deleted.
2055However, the side effect of cleaning up may be that you cannot compare the same
2056buffer in two separate Ediff sessions: quitting one of them will delete this
2057buffer in another session as well."
2058 (or (not (ediff-buffer-live-p ediff-buffer-A))
2059 (buffer-modified-p ediff-buffer-A)
2060 (ediff-kill-buffer-carefully ediff-buffer-A))
2061 (or (not (ediff-buffer-live-p ediff-buffer-B))
2062 (buffer-modified-p ediff-buffer-B)
2063 (ediff-kill-buffer-carefully ediff-buffer-B))
2064 (if ediff-merge-job ; don't del buf C if merging--del ancestor buf instead
2065 (or (not (ediff-buffer-live-p ediff-ancestor-buffer))
2066 (buffer-modified-p ediff-ancestor-buffer)
2067 (ediff-kill-buffer-carefully ediff-ancestor-buffer))
2068 (or (not (ediff-buffer-live-p ediff-buffer-C))
2069 (buffer-modified-p ediff-buffer-C)
2070 (ediff-kill-buffer-carefully ediff-buffer-C))))
2071
475f9031
KH
2072;; The default way of suspending Ediff.
2073;; Buries Ediff buffers, kills all windows.
2074(defun ediff-default-suspend-hook ()
2075 (let* ((buf-A ediff-buffer-A)
2076 (buf-B ediff-buffer-B)
2077 (buf-C ediff-buffer-C)
2078 (buf-A-wind (ediff-get-visible-buffer-window buf-A))
2079 (buf-B-wind (ediff-get-visible-buffer-window buf-B))
2080 (buf-C-wind (ediff-get-visible-buffer-window buf-C))
2081 (buf-patch ediff-patch-buf)
2082 (buf-patch-diag ediff-patch-diagnostics)
2083 (buf-err ediff-error-buffer)
2084 (buf-diff ediff-diff-buffer)
2085 (buf-custom-diff ediff-custom-diff-buffer)
2086 (buf-fine-diff ediff-fine-diff-buffer))
2087
2088 ;; hide the control panel
41d25ad0
KH
2089 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
2090 (iconify-frame ediff-control-frame)
475f9031
KH
2091 (bury-buffer))
2092 (if buf-err (bury-buffer buf-err))
2093 (if buf-diff (bury-buffer buf-diff))
2094 (if buf-custom-diff (bury-buffer buf-custom-diff))
2095 (if buf-fine-diff (bury-buffer buf-fine-diff))
2096 (if buf-patch (bury-buffer buf-patch))
2097 (if buf-patch-diag (bury-buffer buf-patch-diag))
2098 (if (window-live-p buf-A-wind)
2099 (progn
2100 (select-window buf-A-wind)
2101 (delete-other-windows)
2102 (bury-buffer))
2103 (if (ediff-buffer-live-p buf-A) (bury-buffer buf-A)))
2104 (if (window-live-p buf-B-wind)
2105 (progn
2106 (select-window buf-B-wind)
2107 (delete-other-windows)
2108 (bury-buffer))
2109 (if (ediff-buffer-live-p buf-B) (bury-buffer buf-B)))
2110 (if (window-live-p buf-C-wind)
2111 (progn
2112 (select-window buf-C-wind)
2113 (delete-other-windows)
2114 (bury-buffer))
2115 (if (ediff-buffer-live-p buf-C) (bury-buffer buf-C)))
2116
2117 ))
2118
2119
2120(defun ediff-suspend ()
2121 "Suspend Ediff.
2122To resume, switch to the appropriate `Ediff Control Panel'
2123buffer and then type \\[ediff-recenter]. Ediff will automatically set
2124up an appropriate window config."
2125 (interactive)
2126 (let ((key (substitute-command-keys "\\[ediff-recenter]")))
2127 (run-hooks 'ediff-suspend-hooks)
2128 (message
2129 "To resume, switch to Ediff Control Panel and hit `%s'" key)))
2130
2131
2132(defun ediff-status-info ()
2133 "Show the names of the buffers or files being operated on by Ediff.
2134Hit \\[ediff-recenter] to reset the windows afterward."
2135 (interactive)
2136 (with-output-to-temp-buffer " *ediff-info*"
2137 (princ (ediff-version))
2138 (princ "\n\n")
2139 (ediff-eval-in-buffer ediff-buffer-A
2140 (if buffer-file-name
2141 (princ
2142 (format "File A = %S\n" buffer-file-name))
2143 (princ
2144 (format "Buffer A = %S\n" (buffer-name)))))
2145 (ediff-eval-in-buffer ediff-buffer-B
2146 (if buffer-file-name
2147 (princ
2148 (format "File B = %S\n" buffer-file-name))
2149 (princ
2150 (format "Buffer B = %S\n" (buffer-name)))))
2151 (if ediff-3way-job
2152 (ediff-eval-in-buffer ediff-buffer-C
2153 (if buffer-file-name
2154 (princ
2155 (format "File C = %S\n" buffer-file-name))
2156 (princ
2157 (format "Buffer C = %S\n" (buffer-name))))))
2158
2159 (let* ((A-line (ediff-eval-in-buffer ediff-buffer-A
2160 (1+ (count-lines (point-min) (point)))))
2161 (B-line (ediff-eval-in-buffer ediff-buffer-B
2162 (1+ (count-lines (point-min) (point)))))
2163 C-line)
2164 (princ (format "\Buffer A's point is on line %d\n" A-line))
2165 (princ (format "Buffer B's point is on line %d\n" B-line))
2166 (if ediff-3way-job
2167 (progn
2168 (setq C-line (ediff-eval-in-buffer ediff-buffer-C
2169 (1+ (count-lines (point-min) (point)))))
2170 (princ (format "Buffer C's point is on line %d\n" C-line)))))
2171
2172 (princ (format "\nCurrent difference number = %S\n"
2173 (cond ((< ediff-current-difference 0) 'start)
2174 ((>= ediff-current-difference
2175 ediff-number-of-differences) 'end)
2176 (t (1+ ediff-current-difference)))))
2177
2178 (cond (ediff-ignore-similar-regions
2179 (princ "\nSkipping regions that differ only in white space & line breaks"))
2180 (t
2181 (princ "\nNot skipping regions that differ in white space & line breaks")))
2182
2183 (cond ((eq ediff-skip-diff-region-function 'ediff-show-all-diffs)
2184 (princ "\nSelective browsing by regexp is off.\n"))
2185 ((eq ediff-skip-diff-region-function 'ediff-hide-regexp-matches)
2186 (princ
2187 "\nIgnoring regions that match")
2188 (princ
2189 (format
2190 "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n"
2191 ediff-regexp-hide-A ediff-hide-regexp-connective
2192 ediff-regexp-hide-B)))
2193 ((eq ediff-skip-diff-region-function 'ediff-focus-on-regexp-matches)
2194 (princ
2195 "\nFocusing on regions that match")
2196 (princ
2197 (format
2198 "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n"
2199 ediff-regexp-focus-A ediff-focus-regexp-connective
2200 ediff-regexp-focus-B)))
2201 (t (princ "\nSelective browsing via a user-defined method.\n")))
2202
2203 (princ
2204 (format "\nBugs/suggestions: type `%s' while in Ediff Control Panel."
2205 (substitute-command-keys "\\[ediff-submit-report]")))
2206 ))
41d25ad0
KH
2207
2208(defun ediff-documentation ()
2209 "Jump to Ediff's Info file."
2210 (interactive)
2211 (let ((ctl-window ediff-control-window)
2212 (ctl-buf ediff-control-buffer))
475f9031 2213
41d25ad0
KH
2214 (ediff-skip-unsuitable-frames)
2215 (condition-case nil
2216 (progn
2217 (pop-to-buffer (get-buffer-create "*info*"))
2218 (info "ediff")
2219 (message "Type `i' to search for a specific topic"))
2220 (error (beep 1)
2221 (with-output-to-temp-buffer " *ediff-info*"
2222 (princ (format "
2223The Info file for Ediff does not seem to be installed.
2224
2225This file is part of the distribution of %sEmacs.
2226Please contact your system administrator. "
2227 (if ediff-xemacs-p "X" ""))))
2228 (if (window-live-p ctl-window)
2229 (progn
2230 (select-window ctl-window)
2231 (switch-to-buffer ctl-buf)))))))
2232
475f9031
KH
2233
2234
2235\f
2236;;; Support routines
2237
2238;; Select a difference by placing the ASCII flags around the appropriate
2239;; group of lines in the A, B buffers
2240;; This may have to be modified for buffer C, when it will be supported.
2241(defun ediff-select-difference (n)
2242 (if (and (ediff-buffer-live-p ediff-buffer-A)
2243 (ediff-buffer-live-p ediff-buffer-B)
2244 (ediff-valid-difference-p n))
2245 (progn
41d25ad0 2246 (if (and (ediff-window-display-p) ediff-use-faces)
475f9031
KH
2247 (progn
2248 (ediff-highlight-diff n)
2249 (setq ediff-highlighting-style 'face))
2250 (setq ediff-highlighting-style 'ascii)
41d25ad0
KH
2251 (ediff-place-flags-in-buffer
2252 'A ediff-buffer-A ediff-control-buffer n)
2253 (ediff-place-flags-in-buffer
2254 'B ediff-buffer-B ediff-control-buffer n)
475f9031 2255 (if ediff-3way-job
41d25ad0
KH
2256 (ediff-place-flags-in-buffer
2257 'C ediff-buffer-C ediff-control-buffer n))
475f9031
KH
2258 )
2259
2260 (ediff-install-fine-diff-if-necessary n)
475f9031
KH
2261 (run-hooks 'ediff-select-hooks))))
2262
2263
2264;; Unselect a difference by removing the ASCII flags in the buffers.
2265;; This may have to be modified for buffer C, when it will be supported.
2266(defun ediff-unselect-difference (n)
2267 (if (ediff-valid-difference-p n)
2268 (progn
41d25ad0 2269 (cond ((and (ediff-window-display-p) ediff-use-faces)
475f9031
KH
2270 (ediff-unhighlight-diff))
2271 ((eq ediff-highlighting-style 'ascii)
2272 (ediff-remove-flags-from-buffer
2273 ediff-buffer-A
41d25ad0 2274 (ediff-get-diff-overlay n 'A))
475f9031
KH
2275 (ediff-remove-flags-from-buffer
2276 ediff-buffer-B
41d25ad0 2277 (ediff-get-diff-overlay n 'B))
475f9031
KH
2278 (if ediff-3way-job
2279 (ediff-remove-flags-from-buffer
2280 ediff-buffer-C
41d25ad0 2281 (ediff-get-diff-overlay n 'C)))
475f9031 2282 ))
475f9031
KH
2283 (setq ediff-highlighting-style nil)
2284
2285 ;; unhighlight fine diffs
2286 (ediff-set-fine-diff-properties ediff-current-difference 'default)
475f9031
KH
2287 (run-hooks 'ediff-unselect-hooks))))
2288
2289
2290;; Unselects prev diff and selects a new one, if FLAG has value other than
2291;; 'select-only or 'unselect-only. If FLAG is 'select-only, the
2292;; next difference is selected, but the current selection is not
2293;; unselected. If FLAG is 'unselect-only then the current selection is
2294;; unselected, but the next one is not selected. If NO-RECENTER is non-nil,
2295;; don't recenter buffers after selecting/unselecting.
2296;;
475f9031 2297(defun ediff-unselect-and-select-difference (n &optional flag no-recenter)
41d25ad0
KH
2298 (let ((ediff-current-difference n))
2299 (or no-recenter
2300 (ediff-recenter 'no-rehighlight)))
475f9031 2301
41d25ad0
KH
2302 (let ((control-buf ediff-control-buffer))
2303 (unwind-protect
475f9031
KH
2304 (progn
2305 (or (eq flag 'select-only)
2306 (ediff-unselect-difference ediff-current-difference))
2307
475f9031
KH
2308 (or (eq flag 'unselect-only)
2309 (ediff-select-difference n))
2310 (setq ediff-current-difference n)
2311 ) ; end protected section
2312
2313 (ediff-eval-in-buffer control-buf
41d25ad0 2314 (ediff-refresh-mode-lines))
475f9031
KH
2315 )))
2316
2317
2318(defun ediff-read-file-name (prompt default-dir default-file)
2319; This is a modified version of a similar function in `emerge.el'.
2320; PROMPT should not have trailing ': ', so that it can be modified
2321; according to context.
2322; If default-file is set, it should be used as the default value.
2323; If default-dir is non-nil, use it as the default directory.
2324; Otherwise, use the value of Emacs' variable `default-directory.'
2325
2326 ;; hack default-dir if it is not set
2327 (setq default-dir
2328 (file-name-as-directory
2329 (abbreviate-file-name
2330 (expand-file-name (or default-dir
2331 (and default-file
2332 (file-name-directory default-file))
2333 default-directory)))))
2334
2335 ;; strip the directory from default-file
2336 (if default-file
2337 (setq default-file (file-name-nondirectory default-file)))
2338 (if (string= default-file "")
2339 (setq default-file nil))
2340
2341 (let (f)
2342 (setq f (expand-file-name
2343 (read-file-name
2344 (format "%s%s: "
2345 prompt
2346 (if default-file
2347 (concat " (default " default-file ")")
2348 ""))
2349 default-dir
2350 default-file
41d25ad0 2351 t ; must match, no-confirm
475f9031
KH
2352 (if default-file (file-name-directory default-file))
2353 )
2354 default-dir
2355 ))
2356 ;; If user enters a directory name, expand the default file in that
2357 ;; directory. This allows the user to enter a directory name for the
2358 ;; B-file and diff against the default-file in that directory instead
2359 ;; of a DIRED listing!
2360 (if (and (file-directory-p f) default-file)
2361 (setq f (expand-file-name
2362 (file-name-nondirectory default-file) f)))
2363 f))
2364
2365;; If `prefix' is given, then it is used as a prefix for the temp file
2366;; name. Otherwise, `_buffer-name' is used. If `file' is given, use this
2367;; file and don't create a new one.
41d25ad0
KH
2368;; Also, save buffer from START to END in the file.
2369;; START defaults to (point-min), END to (point-max)
475f9031
KH
2370(defun ediff-make-temp-file (&optional prefix given-file start end)
2371 (let ((f (or given-file
2372 (make-temp-name (concat
2373 ediff-temp-file-prefix
2374 (if prefix
2375 (concat prefix "_")
2376 "ediff_"))))))
2377 ;; create the file
2378 (write-region (if start start (point-min))
2379 (if end end (point-max))
2380 f
2381 nil ; don't append---erase
2382 'no-message)
2383 (set-file-modes f ediff-temp-file-mode)
2384 f))
2385
2386;; Quote metacharacters (using \) when executing diff in Unix, but not in
2387;; EMX OS/2
2388(defun ediff-protect-metachars (str)
2389 (or (memq system-type '(emx vax-vms axp-vms))
2390 (let ((limit 0))
2391 (while (string-match ediff-metachars str limit)
2392 (setq str (concat (substring str 0 (match-beginning 0))
2393 "\\"
2394 (substring str (match-beginning 0))))
2395 (setq limit (1+ (match-end 0))))))
2396 str)
2397
2398;; Make sure the current buffer (for a file) has the same contents as the
2399;; file on disk, and attempt to remedy the situation if not.
2400;; Signal an error if we can't make them the same, or the user doesn't want
2401;; to do what is necessary to make them the same.
2402;; If file has file handlers (indicated by the optional arg), then we
2403;; offer to instead of saving. This is one difference with Emerge.
2404;; Another is that we always offer to revert obsolete files, whether they
2405;; are modified or not.
2406(defun ediff-verify-file-buffer (&optional file-magic)
2407 ;; First check if the file has been modified since the buffer visited it.
2408 (if (verify-visited-file-modtime (current-buffer))
2409 (if (buffer-modified-p)
2410 ;; If buffer is not obsolete and is modified, offer to save
2411 (if (yes-or-no-p
2412 (format "Buffer out of sync with visited file. %s file %s? "
2413 (if file-magic "Revert" "Save")
2414 buffer-file-name))
2415 (if (not file-magic)
2416 (save-buffer)
2417 ;; for some reason, file-name-handlers append instead of
2418 ;; replacing, so we have to erase first.
2419 (erase-buffer)
2420 (revert-buffer t t))
2421 (error "Buffer out of sync for file %s" buffer-file-name))
2422 ;; If buffer is not obsolete and is not modified, do nothing
2423 nil)
2424 ;; If buffer is obsolete, offer to revert
2425 (if (yes-or-no-p
2426 (format "Buffer out of sync with visited file. Revert file %s? "
2427 buffer-file-name))
2428 (progn
2429 (if file-magic
2430 (erase-buffer))
2431 (revert-buffer t t))
2432 (error "Buffer out of sync for file %s" buffer-file-name))))
2433
2434
475f9031
KH
2435
2436(defun ediff-check-for-ascii-flags ()
2437 (eval
2438 (cons 'or
2439 (mapcar (function (lambda (buf)
2440 (if (ediff-buffer-live-p buf)
2441 (ediff-eval-in-buffer buf
2442 (eq ediff-highlighting-style 'ascii)))))
2443 ediff-this-buffer-control-sessions))))
2444
2445;; It would be nice to use these two functions as hooks instead of
2446;; ediff-insert-in-front and ediff-move-disturbed-overlays.
2447;; However, Emacs has a bug that causes BEG and END, below, to be
2448;; the same, i.e., the end of inserted text is not passed correctly.
2449;; Since the overlay doesn't move when these hooks run,
2450;; there is no way to correctly determine the new (desired) position of
2451;; the overlay end.
2452;; Either this bug is fixed, or (better) use sticky overlays when they will
2453;; be implemented in Emacs, like they are in XEmacs.
2454;;(defun ediff-capture-inserts-in-front (overl beg end)
2455;; (if (ediff-overlay-get overl 'ediff-diff-num)
2456;; (ediff-move-overlay
2457;; overl beg (+ (- end beg) (ediff-overlay-end overl)))
2458;; ))
2459;;(defun ediff-capture-inserts-behind (overl beg end)
2460;; (if (ediff-overlay-get overl 'ediff-diff-num)
2461;; (ediff-move-overlay overl (ediff-overlay-start overl) end))
2462;; ))
2463
2464;; to be deleted in due time
2465;; Capture overlays that had insertions in the front.
2466;; Called when overlay OVERL gets insertion in front.
2467(defun ediff-insert-in-front (overl &optional flag beg end length)
2468 (if (ediff-overlay-get overl 'ediff-diff-num)
2469 (setq ediff-disturbed-overlays
2470 (cons overl ediff-disturbed-overlays))))
2471
475f9031
KH
2472
2473;; to be deleted in due time
2474;; We can't move overlays directly in insert-in-front-hooks
2475;; because when diff is highlighted with ascii flags, they will disturb
2476;; overlays and so they will be included in them, which we don't want.
2477(defun ediff-move-disturbed-overlays (posn)
2478 (mapcar (function (lambda (overl)
2479 (ediff-move-overlay overl
2480 posn
2481 (ediff-overlay-end overl))
2482 ))
2483 ediff-disturbed-overlays)
2484 (setq ediff-disturbed-overlays nil))
2485
475f9031
KH
2486
2487(defun ediff-save-buffer (arg)
2488 "Safe way of saving buffers A, B, C, and the diff output.
2489`wa' saves buffer A, `wb' saves buffer B, `wc' saves buffer C,
2490and `wd' saves the diff output."
2491 (interactive "P")
41d25ad0
KH
2492 (ediff-eval-in-buffer
2493 (cond ((memq last-command-char '(?a ?b ?c))
2494 (ediff-get-buffer
2495 (ediff-char-to-buftype last-command-char)))
2496 ((eq last-command-char ?d)
2497 (message "Saving diff output ...")(sit-for 1)
2498 (if arg ediff-diff-buffer ediff-custom-diff-buffer)
2499 ))
2500 (save-buffer)))
475f9031
KH
2501
2502
2503;; will simplify it in due time, when emacs acquires before/after strings
41d25ad0 2504(defun ediff-remove-flags-from-buffer (buffer overlay)
475f9031 2505 (ediff-eval-in-buffer buffer
41d25ad0 2506 (let ((inhibit-read-only t))
475f9031
KH
2507 (if ediff-xemacs-p
2508 (ediff-overlay-put overlay 'begin-glyph nil)
2509 ;; before-string is not yet implemented in emacs.
2510 ;; when it will be, I will be able to delete much of the rest of
2511 ;; this function
41d25ad0 2512 (ediff-overlay-put overlay 'before-string nil))
475f9031
KH
2513
2514 (if ediff-xemacs-p
2515 (ediff-overlay-put overlay 'end-glyph nil)
2516 ;; after-string is not yet implemented in emacs.
41d25ad0 2517 (ediff-overlay-put overlay 'after-string nil))
475f9031
KH
2518 )))
2519
2520
2521
2522;; will simplify it in due time, when emacs acquires before/after strings
2523(defun ediff-place-flags-in-buffer (buf-type buffer ctl-buffer diff)
2524 (ediff-eval-in-buffer buffer
2525 (ediff-place-flags-in-buffer1 buf-type ctl-buffer diff)))
2526
2527
2528(defun ediff-place-flags-in-buffer1 (buf-type ctl-buffer diff-no)
41d25ad0 2529 (let* ((curr-overl (ediff-eval-in-buffer ctl-buffer
475f9031 2530 (ediff-get-diff-overlay diff-no buf-type)))
475f9031 2531 (before (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer))
41d25ad0 2532 after beg-of-line flag)
475f9031
KH
2533
2534 ;; insert flag before the difference
2535 (goto-char before)
2536 (setq beg-of-line (bolp))
2537
2538 (setq flag (ediff-eval-in-buffer ctl-buffer
41d25ad0
KH
2539 (if (eq ediff-highlighting-style 'ascii)
2540 (if beg-of-line
2541 ediff-before-flag-bol ediff-before-flag-mol))))
475f9031
KH
2542
2543 ;; insert the flag itself
2544 (if ediff-xemacs-p
2545 (ediff-overlay-put curr-overl 'begin-glyph flag)
41d25ad0 2546 (ediff-overlay-put curr-overl 'before-string flag))
475f9031
KH
2547
2548 ;; insert the flag after the difference
2549 ;; `after' must be set here, after the before-flag was inserted
2550 (setq after (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer))
2551 (goto-char after)
2552 (setq beg-of-line (bolp))
2553
2554 (setq flag (ediff-eval-in-buffer ctl-buffer
41d25ad0
KH
2555 (if (eq ediff-highlighting-style 'ascii)
2556 (if beg-of-line
2557 ediff-after-flag-eol ediff-after-flag-mol))))
475f9031
KH
2558
2559 ;; insert the flag itself
2560 (if ediff-xemacs-p
475f9031 2561 (ediff-overlay-put curr-overl 'end-glyph flag)
41d25ad0 2562 (ediff-overlay-put curr-overl 'after-string flag))
475f9031
KH
2563 ))
2564
2565
2566(defun ediff-get-diff-posn (buf-type pos &optional n control-buf)
2567 "Returns positions of difference sectors in the BUF-TYPE buffer.
2568BUF-TYPE should be a symbol--either `A' or `B'.
2569POS is either `beg' or `end'--it specifies whether you want the position at the
2570beginning of a difference or at the end.
2571
2572The optional argument N says which difference \(default:
2573`ediff-current-difference'\). The optional argument CONTROL-BUF says
2574which control buffer is in effect in case it is not the current
2575buffer."
2576 (let (diff-overlay)
2577 (or control-buf
2578 (setq control-buf (current-buffer)))
2579
2580 (ediff-eval-in-buffer control-buf
2581 (or n (setq n ediff-current-difference))
2582 (if (or (< n 0) (>= n ediff-number-of-differences))
2583 (if (> ediff-number-of-differences 0)
2584 (error "There is no diff %d. Valid diffs are 1 to %d"
2585 (1+ n) ediff-number-of-differences)
2586 (error "No differences found")))
2587 (setq diff-overlay (ediff-get-diff-overlay n buf-type)))
2588
2589 (if (eq pos 'beg)
2590 (ediff-overlay-start diff-overlay)
2591 (ediff-overlay-end diff-overlay))
2592 ))
2593
2594
2595
2596(defun ediff-highlight-diff-in-one-buffer (n buf-type)
2597 (if (ediff-buffer-live-p (ediff-get-buffer buf-type))
2598 (let* ((buff (ediff-get-buffer buf-type))
2599 (last (ediff-eval-in-buffer buff (point-max)))
2600 (begin (ediff-get-diff-posn buf-type 'beg n))
2601 (end (ediff-get-diff-posn buf-type 'end n))
2602 (xtra (if (equal begin end) 1 0))
2603 (end-hilit (min last (+ end xtra)))
2604 (current-diff-overlay
2605 (symbol-value
2606 (intern (format "ediff-current-diff-overlay-%S" buf-type))))
2607 (odd-diff-face
2608 (symbol-value
2609 (intern (format "ediff-odd-diff-face-%S" buf-type))))
2610 (even-diff-face
2611 (symbol-value
2612 (intern (format "ediff-even-diff-face-%S" buf-type))))
2613 (odd-diff-face-var
2614 (intern (format "ediff-odd-diff-face-%S-var" buf-type)))
2615 (even-diff-face-var
2616 (intern (format "ediff-even-diff-face-%S-var" buf-type)))
2617 )
2618
2619 (if ediff-xemacs-p
41d25ad0
KH
2620 (ediff-move-overlay current-diff-overlay begin end-hilit)
2621 (ediff-move-overlay current-diff-overlay begin end-hilit buff))
475f9031
KH
2622 ;; giving priority of 0 and then changing it may look funny, but
2623 ;; this overcomes an obscure Emacs bug.
2624 (ediff-overlay-put current-diff-overlay 'priority 0)
2625 (ediff-overlay-put current-diff-overlay 'priority
2626 (ediff-highest-priority begin end-hilit buff))
2627
2628 (or (face-differs-from-default-p odd-diff-face-var)
2629 (not ediff-highlight-all-diffs)
2630 (progn
2631 (copy-face odd-diff-face odd-diff-face-var)
2632 (copy-face even-diff-face even-diff-face-var)))
2633
2634 ;; unhighlight the background overlay for diff n so they won't
2635 ;; interfere with the current diff overlay
2636 (ediff-overlay-put (ediff-get-diff-overlay n buf-type) 'face nil)
2637 )))
2638
2639
2640(defun ediff-unhighlight-diff-in-one-buffer (buf-type)
2641 (if (ediff-buffer-live-p (ediff-get-buffer buf-type))
2642 (let ((current-diff-overlay
2643 (symbol-value
2644 (intern (format "ediff-current-diff-overlay-%S" buf-type))))
2645 (odd-diff-face-var
2646 (intern (format "ediff-odd-diff-face-%S-var" buf-type)))
2647 (even-diff-face-var
2648 (intern (format "ediff-even-diff-face-%S-var" buf-type)))
2649 (overlay
2650 (ediff-get-diff-overlay ediff-current-difference buf-type))
2651 )
2652
2653 (ediff-move-overlay current-diff-overlay 1 1)
2654
2655 ;; rehighlight the overlay in the background of the
2656 ;; current difference region
2657 (ediff-overlay-put overlay
2658 'face (if (ediff-odd-p ediff-current-difference)
2659 odd-diff-face-var
2660 even-diff-face-var))
2661 )))
2662
2663(defun ediff-unhighlight-diffs-totally-in-one-buffer (buf-type)
41d25ad0
KH
2664 (ediff-unselect-and-select-difference -1)
2665 (if (and (ediff-window-display-p) ediff-use-faces)
2666 (let* ((inhibit-quit t)
2667 (current-diff-overlay-var
2668 (intern (format "ediff-current-diff-overlay-%S" buf-type)))
2669 (current-diff-overlay (symbol-value current-diff-overlay-var))
2670 (odd-diff-face-var
2671 (intern (format "ediff-odd-diff-face-%S-var" buf-type)))
2672 (even-diff-face-var
2673 (intern (format "ediff-even-diff-face-%S-var" buf-type))))
2674 (if (face-differs-from-default-p odd-diff-face-var)
2675 (progn
2676 (copy-face 'default odd-diff-face-var)
2677 (copy-face 'default even-diff-face-var)))
2678 (if (ediff-overlayp current-diff-overlay)
2679 (ediff-delete-overlay current-diff-overlay))
2680 (set current-diff-overlay-var nil)
2681 )))
475f9031
KH
2682
2683
2684;; null out difference overlays so they won't slow down future
2685;; editing operations
2686;; VEC is either a difference vector or a fine-diff vector
2687(defun ediff-clear-diff-vector (vec-var &optional fine-diffs-also)
2688 (if (vectorp (symbol-value vec-var))
2689 (mapcar (function
2690 (lambda (elt)
2691 (ediff-delete-overlay
2692 (ediff-get-diff-overlay-from-diff-record elt))
2693 (if fine-diffs-also
2694 (ediff-clear-fine-diff-vector elt))
2695 ))
2696 (symbol-value vec-var)))
2697 ;; allow them to be garbage collected
2698 (set vec-var nil))
2699
475f9031
KH
2700
2701\f
2702;;; Misc
2703
2704;; These two functions are here to neutralize XEmacs unwillingless to
2705;; handle overlays whose buffers were deleted.
2706(defun ediff-move-overlay (overlay beg end &optional buffer)
2707 "Calls `move-overlay' in Emacs and `set-extent-endpoints' in Lemacs.
2708Checks if overlay's buffer exists before actually doing the move."
2709 (let ((buf (and overlay (ediff-overlay-buffer overlay))))
2710 (if (ediff-buffer-live-p buf)
2711 (if ediff-xemacs-p
41d25ad0 2712 (set-extent-endpoints overlay beg end)
475f9031
KH
2713 (move-overlay overlay beg end buffer))
2714 ;; buffer's dead
2715 (if overlay
2716 (ediff-delete-overlay overlay)))))
2717
2718(defun ediff-overlay-put (overlay prop value)
2719 "Calls `overlay-put' or `set-extent-property' depending on Emacs version.
2720Checks if overlay's buffer exists."
2721 (if (ediff-buffer-live-p (ediff-overlay-buffer overlay))
2722 (if ediff-xemacs-p
2723 (set-extent-property overlay prop value)
2724 (overlay-put overlay prop value))
2725 (ediff-delete-overlay overlay)))
2726
2727
475f9031
KH
2728;; In Emacs, this just makes overlay. In the future, when Emacs will start
2729;; supporting sticky overlays, this function will make a sticky overlay.
2730;; BEG and END are expressions telling where overlay starts.
2731;; If they are numbers or buffers, then all is well. Otherwise, they must
2732;; be expressions to be evaluated in buffer BUF in order to get the overlay
2733;; bounds.
2734;; If BUFF is not a live buffer, then return nil; otherwise, return the
2735;; newly created overlay.
2736(defun ediff-make-bullet-proof-overlay (beg end buff)
2737 (if (ediff-buffer-live-p buff)
2738 (let (overl)
2739 (ediff-eval-in-buffer buff
2740 (or (number-or-marker-p beg)
2741 (setq beg (eval beg)))
2742 (or (number-or-marker-p end)
2743 (setq end (eval end)))
2744 (setq overl (ediff-make-overlay beg end buff))
2745
2746 (if ediff-xemacs-p
2747 (progn
2748 ;; take precautions against detached extents
41d25ad0 2749 (ediff-overlay-put overl 'detachable nil)
475f9031
KH
2750 ;; chars inserted at both ends will be inside extent
2751 (ediff-overlay-put overl 'start-open nil)
2752 (ediff-overlay-put overl 'end-open nil))
2753 (ediff-overlay-put overl 'ediff-diff-num 0)
2754 ;;(ediff-overlay-put overl 'insert-in-front-hooks
2755 ;; (list 'ediff-capture-inserts-in-front))
2756 ;;(ediff-overlay-put overl 'insert-behind-hooks
2757 ;; (list 'ediff-capture-inserts-behind))
2758 ;; These two are not yet implemented in Emacs
2759 ;;(ediff-overlay-put overl 'rear-sticky t)
2760 ;;(ediff-overlay-put overl 'front-sticky t)
2761 )
2762 overl))))
41d25ad0
KH
2763
2764(defsubst ediff-overlay-start (overl)
2765 (if (ediff-overlayp overl)
2766 (if ediff-emacs-p
2767 (overlay-start overl)
2768 (extent-start-position overl))))
2769
2770(defsubst ediff-overlay-end (overl)
2771 (if (ediff-overlayp overl)
2772 (if ediff-emacs-p
2773 (overlay-end overl)
2774 (extent-end-position overl))))
475f9031
KH
2775
2776
475f9031
KH
2777;; Like other-buffer, but prefers visible buffers and ignores temporary or
2778;; other insignificant buffers (those beginning with "^[ *]").
2779;; Gets one arg--buffer name or a list of buffer names (it won't return
2780;; these buffers).
2781(defun ediff-other-buffer (buff)
2782 (if (not (listp buff)) (setq buff (list buff)))
41d25ad0 2783 (let* ((frame-buffers (buffer-list))
475f9031
KH
2784 (significant-buffers
2785 (mapcar
2786 (function (lambda (x)
2787 (cond ((member (buffer-name x) buff)
2788 nil)
2789 ((not (ediff-get-visible-buffer-window x))
2790 nil)
2791 ((string-match "^ " (buffer-name x))
2792 nil)
2793 (t x))))
41d25ad0 2794 frame-buffers))
475f9031
KH
2795 (buffers (delq nil significant-buffers))
2796 less-significant-buffers)
2797
2798 (cond (buffers (car buffers))
2799 ;; try also buffers that are not displayed in windows
2800 ((setq less-significant-buffers
2801 (delq nil
2802 (mapcar
2803 (function
2804 (lambda (x)
2805 (cond ((member (buffer-name x) buff) nil)
2806 ((string-match "^[ *]" (buffer-name x)) nil)
2807 (t x))))
41d25ad0 2808 frame-buffers)))
475f9031
KH
2809 (car less-significant-buffers))
2810 (t (other-buffer (current-buffer))))
2811 ))
2812
2813
2814;; Construct a unique buffer name.
2815;; The first one tried is prefixsuffix, then prefix<2>suffix,
2816;; prefix<3>suffix, etc.
2817(defun ediff-unique-buffer-name (prefix suffix)
2818 (if (null (get-buffer (concat prefix suffix)))
2819 (concat prefix suffix)
2820 (let ((n 2))
2821 (while (get-buffer (format "%s<%d>%s" prefix n suffix))
2822 (setq n (1+ n)))
2823 (format "%s<%d>%s" prefix n suffix))))
2824
2825
475f9031
KH
2826(defun ediff-submit-report ()
2827 "Submit bug report on Ediff."
2828 (interactive)
2829 (let ((reporter-prompt-for-summary-p t)
2830 (ctl-buf ediff-control-buffer)
41d25ad0 2831 (ediff-device-type (ediff-device-type))
475f9031
KH
2832 varlist salutation buffer-name)
2833 (setq varlist '(ediff-diff-program ediff-diff-options
2834 ediff-patch-program ediff-patch-options
2835 ediff-shell
2836 ediff-use-faces
2837 ediff-auto-refine ediff-highlighting-style
2838 ediff-buffer-A ediff-buffer-B ediff-control-buffer
2839 ediff-forward-word-function
2840 ediff-control-frame
2841 ediff-control-frame-parameters
2842 ediff-control-frame-position-function
2843 ediff-prefer-iconified-control-frame
2844 ediff-window-setup-function
2845 ediff-split-window-function
2846 ediff-job-name
2847 ediff-word-mode
2848 buffer-name
41d25ad0 2849 ediff-device-type
475f9031
KH
2850 ))
2851 (setq salutation "
2852Congratulations! You may have unearthed a bug in Ediff!
2853
2854Please make a concise and accurate summary of what happened
2855and mail it to the address above.
2856-----------------------------------------------------------
2857")
2858
2859 (ediff-skip-unsuitable-frames)
41d25ad0 2860 (ediff-reset-mouse)
475f9031
KH
2861
2862 (switch-to-buffer ediff-msg-buffer)
2863 (erase-buffer)
2864 (delete-other-windows)
2865 (insert "
2866Please read this first:
2867----------------------
2868
2869Some ``bugs'' may actually be no bugs at all. For instance, if you are
2870reporting that certain difference regions are not matched as you think they
2871should, this is most likely due to the way Unix diff program decides what
2872constitutes a difference region. Ediff is an Emacs interface to diff, and
2873it has nothing to do with those decisions---it only takes the output from
2874diff and presents it in a way that is better suited for human browsing and
2875manipulation.
2876
2877If Emacs happens to dump core, this is NOT an Ediff problem---it is
2878an Emacs bug. Report this to Emacs maintainers.
2879
2880Another popular topic for reports is compilation messages. Because Ediff
2881interfaces to several other packages and runs under Emacs and XEmacs,
2882byte-compilation may produce output like this:
2883
2884 While compiling toplevel forms in file ediff.el:
2885 ** reference to free variable pm-color-alist
2886 ........................
2887 While compiling the end of the data:
2888 ** The following functions are not known to be defined:
41d25ad0 2889 ediff-valid-color-p, ediff-set-face,
475f9031
KH
2890 ........................
2891
2892These are NOT errors, but inevitable warnings, which ought to be ignored.
2893
2894Please do not report those and similar things. However, comments and
2895suggestions are always welcome.
2896
2897Mail anyway? (y or n) ")
2898
2899 (if (y-or-n-p "Mail anyway? ")
2900 (progn
2901 (if (ediff-buffer-live-p ctl-buf)
2902 (set-buffer ctl-buf))
2903 (setq buffer-name (buffer-name))
2904 (require 'reporter)
2905 (reporter-submit-bug-report "kifer@cs.sunysb.edu"
2906 (ediff-version)
2907 varlist
2908 nil
2909 'delete-other-windows
2910 salutation))
2911 (bury-buffer)
2912 (beep 1)(message "Bug report aborted")
2913 (if (ediff-buffer-live-p ctl-buf)
2914 (ediff-eval-in-buffer ctl-buf
2915 (ediff-recenter 'no-rehighlight))))
2916 ))
2917
2918
2919(defun ediff-union (list1 list2)
2920 "Combine LIST1 and LIST2 using a set-union operation.
2921The result list contains all items that appear in either LIST1 or LIST2.
2922This is a non-destructive function; it makes a copy of the data if necessary
2923to avoid corrupting the original LIST1 and LIST2.
2924This is a slightly simplified version from `cl-seq.el'. Added here to
2925avoid loading cl-*."
2926 (cond ((null list1) list2) ((null list2) list1)
2927 ((equal list1 list2) list1)
2928 (t
2929 (or (>= (length list1) (length list2))
2930 (setq list1 (prog1 list2 (setq list2 list1))))
2931 (while list2
2932 (or (memq (car list2) list1)
2933 (setq list1 (cons (car list2) list1)))
2934 (setq list2 (cdr list2)))
2935 list1)))
2936
2937(defun ediff-deactivate-mark ()
2938 (if ediff-xemacs-p
2939 (zmacs-deactivate-region)
2940 (deactivate-mark)))
2941
2942(cond ((fboundp 'nuke-selective-display)
2943 ;; XEmacs 19.12 has nuke-selective-display
2944 (fset 'ediff-nuke-selective-display 'nuke-selective-display))
2945 (t
2946 (defun ediff-nuke-selective-display ()
2947 (save-excursion
2948 (save-restriction
2949 (widen)
2950 (goto-char (point-min))
2951 (let ((mod-p (buffer-modified-p))
41d25ad0 2952 buffer-read-only end)
475f9031
KH
2953 (and (eq t selective-display)
2954 (while (search-forward "\^M" nil t)
2955 (end-of-line)
2956 (setq end (point))
2957 (beginning-of-line)
2958 (while (search-forward "\^M" end t)
2959 (delete-char -1)
2960 (insert "\^J"))))
2961 (set-buffer-modified-p mod-p)
2962 (setq selective-display nil)))))
2963 ))
2964
2965
41d25ad0 2966;; The next two are modified versions from emerge.el.
475f9031 2967;; VARS must be a list of symbols
41d25ad0
KH
2968;; ediff-save-variables returns an association list: ((var . val) ...)
2969(defsubst ediff-save-variables (vars)
2970 (mapcar (function (lambda (v) (cons v (symbol-value v))))
475f9031 2971 vars))
41d25ad0
KH
2972;; VARS is a list of variable symbols.
2973(defun ediff-restore-variables (vars assoc-list)
475f9031 2974 (while vars
41d25ad0
KH
2975 (set (car vars) (cdr (assoc (car vars) assoc-list)))
2976 (setq vars (cdr vars))))
2977(defun ediff-change-saved-variable (var value buf-type)
2978 (let* ((assoc-list
2979 (symbol-value (intern
2980 (concat "ediff-buffer-values-orig-"
2981 (symbol-name buf-type)))))
2982 (assoc-elt (assoc var assoc-list)))
2983 (if assoc-elt
2984 (setcdr assoc-elt value))))
2985
475f9031
KH
2986
2987;; must execute in control buf
2988(defun ediff-save-protected-variables ()
41d25ad0 2989 (setq ediff-buffer-values-orig-A
475f9031
KH
2990 (ediff-eval-in-buffer ediff-buffer-A
2991 (ediff-save-variables ediff-protected-variables)))
41d25ad0 2992 (setq ediff-buffer-values-orig-B
475f9031
KH
2993 (ediff-eval-in-buffer ediff-buffer-B
2994 (ediff-save-variables ediff-protected-variables)))
2995 (if ediff-3way-comparison-job
41d25ad0 2996 (setq ediff-buffer-values-orig-C
475f9031
KH
2997 (ediff-eval-in-buffer ediff-buffer-C
2998 (ediff-save-variables ediff-protected-variables)))))
2999
3000;; must execute in control buf
3001(defun ediff-restore-protected-variables ()
41d25ad0
KH
3002 (let ((values-A ediff-buffer-values-orig-A)
3003 (values-B ediff-buffer-values-orig-B)
3004 (values-C ediff-buffer-values-orig-C))
475f9031
KH
3005 (ediff-eval-in-buffer ediff-buffer-A
3006 (ediff-restore-variables ediff-protected-variables values-A))
3007 (ediff-eval-in-buffer ediff-buffer-B
3008 (ediff-restore-variables ediff-protected-variables values-B))
3009 (if ediff-3way-comparison-job
3010 (ediff-eval-in-buffer ediff-buffer-C
3011 (ediff-restore-variables ediff-protected-variables values-C)))))
3012
475f9031
KH
3013
3014;;; Debug
3015
3016(ediff-defvar-local ediff-command-begin-time '(0 0 0) "")
3017
3018;; calculate time used by command
3019(defun ediff-calc-command-time ()
3020 (let ((end (current-time))
3021 micro sec)
3022 (setq micro
3023 (if (>= (nth 2 end) (nth 2 ediff-command-begin-time))
3024 (- (nth 2 end) (nth 2 ediff-command-begin-time))
3025 (+ (nth 2 end) (- 1000000 (nth 2 ediff-command-begin-time)))))
3026 (setq sec (- (nth 1 end) (nth 1 ediff-command-begin-time)))
3027 (or (equal ediff-command-begin-time '(0 0 0))
3028 (message "Elapsed time: %d second(s) + %d microsecond(s)" sec micro))))
3029
3030(defsubst ediff-save-time ()
3031 (setq ediff-command-begin-time (current-time)))
3032
3033(defun ediff-profile ()
3034 "Toggle profiling Ediff commands."
3035 (interactive)
3036 (or (ediff-buffer-live-p ediff-control-buffer)
3037 (error "This command runs only out of Ediff Control Buffer"))
3038 (make-local-variable 'pre-command-hook)
3039 (make-local-variable 'post-command-hook)
3040 (if (memq 'ediff-save-time pre-command-hook)
3041 (progn (remove-hook 'pre-command-hook 'ediff-save-time)
3042 (remove-hook 'post-command-hook 'ediff-calc-command-time)
3043 (setq ediff-command-begin-time '(0 0 0))
3044 (message "Ediff profiling disabled"))
3045 (add-hook 'pre-command-hook 'ediff-save-time t)
3046 (add-hook 'post-command-hook 'ediff-calc-command-time)
3047 (message "Ediff profiling enabled")))
3048
3049(defun ediff-print-diff-vector (diff-vector-var)
3050 (princ (format "\n*** %S ***\n" diff-vector-var))
3051 (mapcar (function
3052 (lambda (overl-vec)
3053 (princ
3054 (format
3055 "Diff %d: \tOverlay: %S
3056\t\tFine diffs: %s
3057\t\tNo-fine-diff-flag: %S
3058\t\tState-of-diff:\t %S
3059\t\tState-of-merge:\t %S
3060"
3061 (1+ (ediff-overlay-get (aref overl-vec 0) 'ediff-diff-num))
3062 (aref overl-vec 0)
3063 ;; fine-diff-vector
3064 (if (= (length (aref overl-vec 1)) 0)
3065 "none\n"
3066 (mapconcat 'prin1-to-string
3067 (aref overl-vec 1) "\n\t\t\t "))
3068 (aref overl-vec 2) ; no fine diff flag
3069 (aref overl-vec 3) ; state-of-diff
3070 (aref overl-vec 4) ; state-of-merge
3071 ))))
3072 (eval diff-vector-var)))
3073
3074
3075
3076(defun ediff-debug-info ()
3077 (interactive)
3078 (or (ediff-buffer-live-p ediff-control-buffer)
3079 (error "This command runs only out of Ediff Control Buffer"))
3080 (with-output-to-temp-buffer ediff-debug-buffer
3081 (princ (format "\nCtl buffer: %S\n" ediff-control-buffer))
3082 (ediff-print-diff-vector (intern (concat "ediff-difference-vector-" "A")))
3083 (ediff-print-diff-vector (intern (concat "ediff-difference-vector-" "B")))
3084 (ediff-print-diff-vector (intern (concat "ediff-difference-vector-" "C")))
3085 ))
3086
3087;; don't report error if version control package wasn't found
3088;;(ediff-load-version-control 'silent)
3089
3090(run-hooks 'ediff-load-hooks)
3091
41d25ad0 3092
475f9031
KH
3093;;; Local Variables:
3094;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
3095;;; eval: (put 'ediff-eval-in-buffer 'lisp-indent-hook 1)
3096;;; End:
3097
3098(provide 'ediff-util)
3099
3100;;; ediff-util.el ends here