(encode_coding_iso2022): Don't skip a code following some invalid code.
[bpt/emacs.git] / lisp / ediff-util.el
CommitLineData
475f9031 1;;; ediff-util.el --- the core commands and utilities of ediff
b578f267 2
ddc90f39 3;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
475f9031
KH
4
5;; Author: Michael Kifer <kifer@cs.sunysb.edu>
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 2, or (at your option)
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
b578f267
EN
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22;; Boston, MA 02111-1307, USA.
475f9031
KH
23
24;;; Code:
ddc90f39
MK
25
26(provide 'ediff-util)
475f9031 27
ddc90f39
MK
28;; Compiler pacifier
29(defvar ediff-patch-diagnostics)
30(defvar ediff-patchbufer)
31(defvar ediff-toolbar)
32(defvar ediff-toolbar-3way)
33(defvar bottom-toolbar)
34(defvar bottom-toolbar-visible-p)
35(defvar bottom-toolbar-height)
36(defvar mark-active)
37
38(eval-when-compile
39 (let ((load-path (cons (expand-file-name ".") load-path)))
40 (or (featurep 'ediff-init)
41 (load "ediff-init.el" nil nil 'nosuffix))
42 (or (featurep 'ediff-help)
43 (load "ediff-help.el" nil nil 'nosuffix))
44 (or (featurep 'ediff-mult)
45 (load "ediff-mult.el" nil nil 'nosuffix))
46 (or (featurep 'ediff-wind)
47 (load "ediff-wind.el" nil nil 'nosuffix))
48 (or (featurep 'ediff-diff)
49 (load "ediff-diff.el" nil nil 'nosuffix))
50 (or (featurep 'ediff-merg)
51 (load "ediff-merg.el" nil nil 'nosuffix))
52 (or (featurep 'ediff)
53 (load "ediff.el" nil nil 'nosuffix))
54 (or (featurep 'ediff-tbar)
55 (load "ediff-tbar.el" 'noerror nil 'nosuffix))
56 ))
bbe6126c
MK
57;; end pacifier
58
bf5d92c5
MK
59(require 'ediff-init)
60(require 'ediff-help)
61(require 'ediff-mult)
ddc90f39
MK
62(require 'ediff-wind)
63(require 'ediff-diff)
64(require 'ediff-merg)
bf5d92c5 65
ddc90f39
MK
66
67;; be careful with ediff-tbar
68(if ediff-xemacs-p
69 (condition-case nil
70 (require 'ediff-tbar)
71 (error
72 (defun ediff-use-toolbar-p () nil)))
73 (defun ediff-use-toolbar-p () nil))
bf5d92c5 74
475f9031
KH
75\f
76;;; Functions
77
78(defun ediff-mode ()
651342bc
MK
79 "Ediff mode controls all operations in a single Ediff session.
80This mode is entered through one of the following commands:
475f9031
KH
81 `ediff'
82 `ediff-files'
83 `ediff-buffers'
bbe6126c 84 `ebuffers'
475f9031
KH
85 `ediff3'
86 `ediff-files3'
87 `ediff-buffers3'
bbe6126c 88 `ebuffers3'
475f9031
KH
89 `ediff-merge'
90 `ediff-merge-files'
91 `ediff-merge-files-with-ancestor'
92 `ediff-merge-buffers'
93 `ediff-merge-buffers-with-ancestor'
94 `ediff-merge-revisions'
95 `ediff-merge-revisions-with-ancestor'
41d25ad0
KH
96 `ediff-windows-wordwise'
97 `ediff-windows-linewise'
98 `ediff-regions-wordwise'
99 `ediff-regions-linewise'
475f9031
KH
100 `epatch'
101 `ediff-patch-file'
102 `ediff-patch-buffer'
103 `epatch-buffer'
1e70790f 104 `erevision'
475f9031
KH
105 `ediff-revision'
106
107Commands:
108\\{ediff-mode-map}"
109 (kill-all-local-variables)
110 (setq major-mode 'ediff-mode)
111 (setq mode-name "Ediff")
651342bc 112 (run-hooks 'ediff-mode-hook))
475f9031 113
475f9031 114
475f9031
KH
115\f
116;;; Build keymaps
117
118(ediff-defvar-local ediff-mode-map nil
119 "Local keymap used in Ediff mode.
120This is local to each Ediff Control Panel, so they may vary from invocation
121to invocation.")
122
123;; Set up the keymap in the control buffer
124(defun ediff-set-keys ()
125 "Set up Ediff keymap, if necessary."
126 (if (null ediff-mode-map)
127 (ediff-setup-keymap))
128 (use-local-map ediff-mode-map))
129
130;; Reload Ediff keymap. For debugging only.
131(defun ediff-reload-keymap ()
132 (interactive)
133 (setq ediff-mode-map nil)
134 (ediff-set-keys))
135
136
137(defun ediff-setup-keymap ()
138 "Set up the keymap used in the control buffer of Ediff."
139 (setq ediff-mode-map (make-sparse-keymap))
140 (suppress-keymap ediff-mode-map)
141
92c51e07
MK
142 (define-key ediff-mode-map
143 (if ediff-emacs-p [mouse-2] [button2]) 'ediff-help-for-quick-help)
144 (define-key ediff-mode-map "\C-m" 'ediff-help-for-quick-help)
145
475f9031
KH
146 (define-key ediff-mode-map "p" 'ediff-previous-difference)
147 (define-key ediff-mode-map "\C-?" 'ediff-previous-difference)
475f9031
KH
148 (define-key ediff-mode-map [delete] 'ediff-previous-difference)
149 (define-key ediff-mode-map "\C-h" (if ediff-no-emacs-help-in-control-buffer
150 'ediff-previous-difference nil))
bd698e98
MK
151 ;; must come after C-h, or else C-h wipes out backspace's binding in XEmacs
152 (define-key ediff-mode-map [backspace] 'ediff-previous-difference)
475f9031
KH
153 (define-key ediff-mode-map "n" 'ediff-next-difference)
154 (define-key ediff-mode-map " " 'ediff-next-difference)
155 (define-key ediff-mode-map "j" 'ediff-jump-to-difference)
156 (define-key ediff-mode-map "g" nil)
157 (define-key ediff-mode-map "ga" 'ediff-jump-to-difference-at-point)
158 (define-key ediff-mode-map "gb" 'ediff-jump-to-difference-at-point)
159 (define-key ediff-mode-map "q" 'ediff-quit)
651342bc 160 (define-key ediff-mode-map "D" 'ediff-show-diff-output)
475f9031
KH
161 (define-key ediff-mode-map "z" 'ediff-suspend)
162 (define-key ediff-mode-map "\C-l" 'ediff-recenter)
163 (define-key ediff-mode-map "|" 'ediff-toggle-split)
164 (define-key ediff-mode-map "h" 'ediff-toggle-hilit)
165 (or ediff-word-mode
166 (define-key ediff-mode-map "@" 'ediff-toggle-autorefine))
41d25ad0 167 (if ediff-narrow-job
475f9031
KH
168 (define-key ediff-mode-map "%" 'ediff-toggle-narrow-region))
169 (define-key ediff-mode-map "~" 'ediff-swap-buffers)
170 (define-key ediff-mode-map "v" 'ediff-scroll-vertically)
171 (define-key ediff-mode-map "\C-v" 'ediff-scroll-vertically)
172 (define-key ediff-mode-map "^" 'ediff-scroll-vertically)
173 (define-key ediff-mode-map "\M-v" 'ediff-scroll-vertically)
174 (define-key ediff-mode-map "V" 'ediff-scroll-vertically)
175 (define-key ediff-mode-map "<" 'ediff-scroll-horizontally)
176 (define-key ediff-mode-map ">" 'ediff-scroll-horizontally)
177 (define-key ediff-mode-map "i" 'ediff-status-info)
651342bc 178 (define-key ediff-mode-map "E" 'ediff-documentation)
475f9031
KH
179 (define-key ediff-mode-map "?" 'ediff-toggle-help)
180 (define-key ediff-mode-map "!" 'ediff-update-diffs)
328b4b70 181 (define-key ediff-mode-map "M" 'ediff-show-current-session-meta-buffer)
651342bc 182 (define-key ediff-mode-map "R" 'ediff-show-registry)
475f9031
KH
183 (or ediff-word-mode
184 (define-key ediff-mode-map "*" 'ediff-make-or-kill-fine-diffs))
185 (define-key ediff-mode-map "a" nil)
186 (define-key ediff-mode-map "b" nil)
187 (define-key ediff-mode-map "r" nil)
188 (cond (ediff-merge-job
651342bc
MK
189 ;; Will barf if no ancestor
190 (define-key ediff-mode-map "/" 'ediff-show-ancestor)
475f9031 191 ;; In merging, we allow only A->C and B->C copying.
4ae69eac
MK
192 (define-key ediff-mode-map "a" 'ediff-copy-A-to-C)
193 (define-key ediff-mode-map "b" 'ediff-copy-B-to-C)
194 (define-key ediff-mode-map "r" 'ediff-restore-diff-in-merge-buffer)
475f9031
KH
195 (define-key ediff-mode-map "s" 'ediff-shrink-window-C)
196 (define-key ediff-mode-map "+" 'ediff-combine-diffs)
197 (define-key ediff-mode-map "$" 'ediff-toggle-show-clashes-only)
198 (define-key ediff-mode-map "&" 'ediff-re-merge))
199 (ediff-3way-comparison-job
4ae69eac
MK
200 (define-key ediff-mode-map "ab" 'ediff-copy-A-to-B)
201 (define-key ediff-mode-map "ba" 'ediff-copy-B-to-A)
202 (define-key ediff-mode-map "ac" 'ediff-copy-A-to-C)
203 (define-key ediff-mode-map "bc" 'ediff-copy-B-to-C)
475f9031 204 (define-key ediff-mode-map "c" nil)
4ae69eac
MK
205 (define-key ediff-mode-map "ca" 'ediff-copy-C-to-A)
206 (define-key ediff-mode-map "cb" 'ediff-copy-C-to-B)
475f9031
KH
207 (define-key ediff-mode-map "ra" 'ediff-restore-diff)
208 (define-key ediff-mode-map "rb" 'ediff-restore-diff)
209 (define-key ediff-mode-map "rc" 'ediff-restore-diff)
210 (define-key ediff-mode-map "C" 'ediff-toggle-read-only))
211 (t ; 2-way comparison
4ae69eac
MK
212 (define-key ediff-mode-map "a" 'ediff-copy-A-to-B)
213 (define-key ediff-mode-map "b" 'ediff-copy-B-to-A)
475f9031
KH
214 (define-key ediff-mode-map "ra" 'ediff-restore-diff)
215 (define-key ediff-mode-map "rb" 'ediff-restore-diff))
216 ) ; cond
217 (define-key ediff-mode-map "G" 'ediff-submit-report)
218 (define-key ediff-mode-map "#" nil)
219 (define-key ediff-mode-map "#h" 'ediff-toggle-regexp-match)
220 (define-key ediff-mode-map "#f" 'ediff-toggle-regexp-match)
221 (or ediff-word-mode
222 (define-key ediff-mode-map "##" 'ediff-toggle-skip-similar))
223 (define-key ediff-mode-map "o" nil)
224 (define-key ediff-mode-map "A" 'ediff-toggle-read-only)
225 (define-key ediff-mode-map "B" 'ediff-toggle-read-only)
226 (define-key ediff-mode-map "w" nil)
227 (define-key ediff-mode-map "wa" 'ediff-save-buffer)
228 (define-key ediff-mode-map "wb" 'ediff-save-buffer)
229 (define-key ediff-mode-map "wd" 'ediff-save-buffer)
92c51e07 230 (define-key ediff-mode-map "=" 'ediff-inferior-compare-regions)
bbe6126c
MK
231 (if (fboundp 'ediff-show-patch-diagnostics)
232 (define-key ediff-mode-map "P" 'ediff-show-patch-diagnostics))
475f9031
KH
233 (if ediff-3way-job
234 (progn
235 (define-key ediff-mode-map "wc" 'ediff-save-buffer)
236 (define-key ediff-mode-map "gc" 'ediff-jump-to-difference-at-point)
237 ))
238
239 (define-key ediff-mode-map "m" 'ediff-toggle-wide-display)
240
475f9031
KH
241 ;; Allow ediff-mode-map to be referenced indirectly
242 (fset 'ediff-mode-map ediff-mode-map)
651342bc 243 (run-hooks 'ediff-keymap-setup-hook))
475f9031
KH
244
245
246;;; Setup functions
247
ddc90f39
MK
248;; Common startup entry for all Ediff functions It now returns control buffer
249;; so other functions can do post-processing SETUP-PARAMETERS is a list of the
250;; form ((param .val) (param . val)...) This serves a similar purpose to
251;; STARTUP-HOOKS, but these parameters are set in the new control buffer right
252;; after this buf is created and before any windows are set and such.
475f9031 253(defun ediff-setup (buffer-A file-A buffer-B file-B buffer-C file-C
328b4b70
MK
254 startup-hooks setup-parameters
255 &optional merge-buffer-file)
92c51e07
MK
256 ;; ediff-convert-standard-filename puts file names in the form appropriate
257 ;; for the OS at hand.
258 (setq file-A (ediff-convert-standard-filename (expand-file-name file-A)))
259 (setq file-B (ediff-convert-standard-filename (expand-file-name file-B)))
475f9031 260 (if (stringp file-C)
92c51e07
MK
261 (setq file-C
262 (ediff-convert-standard-filename (expand-file-name file-C))))
328b4b70
MK
263 (if (stringp merge-buffer-file)
264 (progn
265 (setq merge-buffer-file
266 (ediff-convert-standard-filename
267 (expand-file-name merge-buffer-file)))
268 ;; check the directory exists
269 (or (file-exists-p (file-name-directory merge-buffer-file))
270 (error "Directory %s given as place to save the merge doesn't exist."
271 (abbreviate-file-name
272 (file-name-directory merge-buffer-file))))
273 (if (and (file-exists-p merge-buffer-file)
274 (file-directory-p merge-buffer-file))
275 (error "The merge buffer file %s must not be a directory"
276 (abbreviate-file-name merge-buffer-file)))
277 ))
475f9031
KH
278 (let* ((control-buffer-name
279 (ediff-unique-buffer-name "*Ediff Control Panel" "*"))
e756eb9f 280 (control-buffer (ediff-with-current-buffer buffer-A
475f9031 281 (get-buffer-create control-buffer-name))))
e756eb9f 282 (ediff-with-current-buffer control-buffer
475f9031 283 (ediff-mode)
ddc90f39
MK
284
285 (make-local-variable 'ediff-use-long-help-message)
286 (make-local-variable 'ediff-prefer-iconified-control-frame)
287 (make-local-variable 'ediff-split-window-function)
288 (make-local-variable 'ediff-default-variant)
289 (make-local-variable 'ediff-merge-window-share)
290 (make-local-variable 'ediff-window-setup-function)
291 (make-local-variable 'ediff-keep-variants)
475f9031
KH
292
293 ;; unwrap set up parameters passed as argument
294 (while setup-parameters
295 (set (car (car setup-parameters)) (cdr (car setup-parameters)))
296 (setq setup-parameters (cdr setup-parameters)))
297
298 ;; set variables classifying the current ediff job
ddc90f39 299 ;; must come AFTER setup-parameters
475f9031
KH
300 (setq ediff-3way-comparison-job (ediff-3way-comparison-job)
301 ediff-merge-job (ediff-merge-job)
302 ediff-merge-with-ancestor-job (ediff-merge-with-ancestor-job)
303 ediff-3way-job (ediff-3way-job)
304 ediff-diff3-job (ediff-diff3-job)
41d25ad0
KH
305 ediff-narrow-job (ediff-narrow-job)
306 ediff-windows-job (ediff-windows-job)
475f9031 307 ediff-word-mode-job (ediff-word-mode-job))
651342bc
MK
308
309 ;; Don't delete variants in case of ediff-buffer-* jobs without asking.
310 ;; This is because u may loose work---dangerous.
311 (if (string-match "buffer" (symbol-name ediff-job-name))
312 (setq ediff-keep-variants t))
313
4ae69eac
MK
314 (make-local-hook 'pre-command-hook)
315 (if (ediff-window-display-p)
bbe6126c 316 (add-hook 'pre-command-hook 'ediff-spy-after-mouse nil t))
651342bc 317 (setq ediff-mouse-pixel-position (mouse-pixel-position))
475f9031
KH
318
319 ;; adjust for merge jobs
320 (if ediff-merge-job
321 (let ((buf
651342bc 322 ;; If default variant is `combined', the right stuff is
475f9031 323 ;; inserted by ediff-do-merge
651342bc
MK
324 ;; Note: at some point, we tried to put ancestor buffer here
325 ;; (which is currently buffer C. This didn't work right
326 ;; because the merge buffer will contain lossage: diff regions
327 ;; in the ancestor, which correspond to revisions that agree
328 ;; in both buf A and B.
329 (cond ((eq ediff-default-variant 'default-B)
330 buffer-B)
331 (t buffer-A))))
475f9031
KH
332
333 (setq ediff-split-window-function
334 ediff-merge-split-window-function)
335
336 ;; remember the ancestor buffer, if any
337 (setq ediff-ancestor-buffer buffer-C)
338
339 (setq buffer-C
340 (get-buffer-create
341 (ediff-unique-buffer-name "*ediff-merge" "*")))
342 (save-excursion
343 (set-buffer buffer-C)
41d25ad0 344 (insert-buffer buf)
e756eb9f 345 (funcall (ediff-with-current-buffer buf major-mode))
bbe6126c 346 (add-hook 'local-write-file-hooks 'ediff-set-merge-mode nil t)
41d25ad0 347 )))
475f9031
KH
348 (setq buffer-read-only nil
349 ediff-buffer-A buffer-A
350 ediff-buffer-B buffer-B
351 ediff-buffer-C buffer-C
352 ediff-control-buffer control-buffer)
353
354 (setq ediff-control-buffer-suffix
355 (if (string-match "<[0-9]*>" control-buffer-name)
356 (substring control-buffer-name
357 (match-beginning 0) (match-end 0))
358 "")
359 ediff-control-buffer-number
360 (max
361 0
362 (1-
363 (string-to-number
364 (substring
365 ediff-control-buffer-suffix
366 (or
367 (string-match "[0-9]+" ediff-control-buffer-suffix)
368 0))))))
369
651342bc
MK
370 (setq ediff-error-buffer
371 (get-buffer-create (ediff-unique-buffer-name "*ediff-errors" "*")))
475f9031 372
e756eb9f
MK
373 (ediff-with-current-buffer buffer-A (ediff-strip-mode-line-format))
374 (ediff-with-current-buffer buffer-B (ediff-strip-mode-line-format))
475f9031 375 (if ediff-3way-job
e756eb9f 376 (ediff-with-current-buffer buffer-C (ediff-strip-mode-line-format)))
651342bc 377 (if (ediff-buffer-live-p ediff-ancestor-buffer)
e756eb9f 378 (ediff-with-current-buffer ediff-ancestor-buffer
651342bc 379 (ediff-strip-mode-line-format)))
475f9031
KH
380
381 (ediff-save-protected-variables) ; save variables to be restored on exit
382
475f9031
KH
383 ;; ediff-setup-diff-regions-function must be set after setup
384 ;; parameters are processed.
385 (setq ediff-setup-diff-regions-function
386 (if ediff-diff3-job
387 'ediff-setup-diff-regions3
388 'ediff-setup-diff-regions))
41d25ad0 389
475f9031
KH
390 (setq ediff-wide-bounds
391 (list (ediff-make-bullet-proof-overlay
392 '(point-min) '(point-max) ediff-buffer-A)
393 (ediff-make-bullet-proof-overlay
394 '(point-min) '(point-max) ediff-buffer-B)
395 (ediff-make-bullet-proof-overlay
396 '(point-min) '(point-max) ediff-buffer-C)))
397
398 ;; This has effect only on ediff-windows/regions
399 ;; In all other cases, ediff-visible-region sets visibility bounds to
400 ;; ediff-wide-bounds, and ediff-narrow-bounds are ignored.
401 (if ediff-start-narrowed
402 (setq ediff-visible-bounds ediff-narrow-bounds)
403 (setq ediff-visible-bounds ediff-wide-bounds))
404
405 (ediff-set-keys) ; comes after parameter setup
406
407 ;; set up ediff-narrow-bounds, if not set
408 (or ediff-narrow-bounds
409 (setq ediff-narrow-bounds ediff-wide-bounds))
410
e756eb9f 411 ;; All these must be inside ediff-with-current-buffer control-buffer,
475f9031
KH
412 ;; since these vars are local to control-buffer
413 ;; These won't run if there are errors in diff
e756eb9f 414 (ediff-with-current-buffer ediff-buffer-A
475f9031 415 (ediff-nuke-selective-display)
651342bc 416 (run-hooks 'ediff-prepare-buffer-hook)
e756eb9f 417 (if (ediff-with-current-buffer control-buffer ediff-merge-job)
475f9031 418 (setq buffer-read-only t))
41d25ad0
KH
419 ;; add control-buffer to the list of sessions--no longer used, but may
420 ;; be used again in the future
651342bc
MK
421 (or (memq control-buffer ediff-this-buffer-ediff-sessions)
422 (setq ediff-this-buffer-ediff-sessions
423 (cons control-buffer ediff-this-buffer-ediff-sessions)))
1e70790f
MK
424 (if ediff-make-buffers-readonly-at-startup
425 (setq buffer-read-only t))
475f9031 426 )
1e70790f 427
e756eb9f 428 (ediff-with-current-buffer ediff-buffer-B
475f9031 429 (ediff-nuke-selective-display)
651342bc 430 (run-hooks 'ediff-prepare-buffer-hook)
e756eb9f 431 (if (ediff-with-current-buffer control-buffer ediff-merge-job)
475f9031 432 (setq buffer-read-only t))
475f9031 433 ;; add control-buffer to the list of sessions
651342bc
MK
434 (or (memq control-buffer ediff-this-buffer-ediff-sessions)
435 (setq ediff-this-buffer-ediff-sessions
436 (cons control-buffer ediff-this-buffer-ediff-sessions)))
1e70790f
MK
437 (if ediff-make-buffers-readonly-at-startup
438 (setq buffer-read-only t))
475f9031 439 )
1e70790f 440
475f9031 441 (if ediff-3way-job
e756eb9f 442 (ediff-with-current-buffer ediff-buffer-C
475f9031 443 (ediff-nuke-selective-display)
651342bc 444 (run-hooks 'ediff-prepare-buffer-hook)
475f9031 445 ;; add control-buffer to the list of sessions
651342bc
MK
446 (or (memq control-buffer ediff-this-buffer-ediff-sessions)
447 (setq ediff-this-buffer-ediff-sessions
475f9031 448 (cons control-buffer
651342bc 449 ediff-this-buffer-ediff-sessions)))
1e70790f
MK
450 (if ediff-make-buffers-readonly-at-startup
451 (setq buffer-read-only t))
651342bc
MK
452 ))
453
454 (if (ediff-buffer-live-p ediff-ancestor-buffer)
e756eb9f 455 (ediff-with-current-buffer ediff-ancestor-buffer
651342bc
MK
456 (ediff-nuke-selective-display)
457 (setq buffer-read-only t)
458 (run-hooks 'ediff-prepare-buffer-hook)
459 (or (memq control-buffer ediff-this-buffer-ediff-sessions)
460 (setq ediff-this-buffer-ediff-sessions
461 (cons control-buffer
462 ediff-this-buffer-ediff-sessions)))
475f9031
KH
463 ))
464
465 ;; must come after setting up ediff-narrow-bounds AND after
466 ;; nuking selective display
467 (funcall ediff-setup-diff-regions-function file-A file-B file-C)
468 (setq ediff-number-of-differences (length ediff-difference-vector-A))
469 (setq ediff-current-difference -1)
470
471 (ediff-make-current-diff-overlay 'A)
472 (ediff-make-current-diff-overlay 'B)
473 (if ediff-3way-job
474 (ediff-make-current-diff-overlay 'C))
651342bc
MK
475 (if ediff-merge-with-ancestor-job
476 (ediff-make-current-diff-overlay 'Ancestor))
475f9031
KH
477
478 (ediff-setup-windows buffer-A buffer-B buffer-C control-buffer)
479
480 (let ((shift-A (ediff-overlay-start
481 (ediff-get-value-according-to-buffer-type
482 'A ediff-narrow-bounds)))
483 (shift-B (ediff-overlay-start
484 (ediff-get-value-according-to-buffer-type
485 'B ediff-narrow-bounds)))
486 (shift-C (ediff-overlay-start
487 (ediff-get-value-according-to-buffer-type
488 'C ediff-narrow-bounds))))
489 ;; position point in buf A
490 (save-excursion
491 (select-window ediff-window-A)
492 (goto-char shift-A))
493 ;; position point in buf B
494 (save-excursion
495 (select-window ediff-window-B)
496 (goto-char shift-B))
497 (if ediff-3way-job
498 (save-excursion
499 (select-window ediff-window-C)
500 (goto-char shift-C)))
501 )
502
503 (select-window ediff-control-window)
504 (ediff-visible-region)
505
651342bc 506 (run-hooks 'startup-hooks)
328b4b70
MK
507 (ediff-arrange-autosave-in-merge-jobs merge-buffer-file)
508
475f9031 509 (ediff-refresh-mode-lines)
651342bc
MK
510 (setq buffer-read-only t)
511 (setq ediff-session-registry
512 (cons control-buffer ediff-session-registry))
513 (ediff-update-registry)
514 (if (ediff-buffer-live-p ediff-meta-buffer)
328b4b70
MK
515 (ediff-update-meta-buffer
516 ediff-meta-buffer nil ediff-meta-session-number))
651342bc
MK
517 (run-hooks 'ediff-startup-hook)
518 ) ; eval in control-buffer
41d25ad0 519 control-buffer))
475f9031
KH
520
521
522;; This function assumes that we are in the window where control buffer is
523;; to reside.
524(defun ediff-setup-control-buffer (ctl-buf)
525 "Set up window for control buffer."
526 (if (window-dedicated-p (selected-window))
527 (set-buffer ctl-buf) ; we are in control frame but just in case
528 (switch-to-buffer ctl-buf))
41d25ad0 529 (let ((window-min-height 2))
475f9031
KH
530 (erase-buffer)
531 (ediff-set-help-message)
532 (insert ediff-help-message)
533 (shrink-window-if-larger-than-buffer)
41d25ad0 534 (or (ediff-multiframe-setup-p)
475f9031 535 (ediff-indent-help-message))
92c51e07
MK
536 (ediff-set-help-overlays)
537
475f9031
KH
538 (set-buffer-modified-p nil)
539 (ediff-refresh-mode-lines)
540 (setq ediff-control-window (selected-window))
541 (setq ediff-window-config-saved
41d25ad0 542 (format "%S%S%S%S%S%S%S"
475f9031
KH
543 ediff-control-window
544 ediff-window-A
545 ediff-window-B
546 ediff-window-C
41d25ad0
KH
547 ediff-split-window-function
548 (ediff-multiframe-setup-p)
549 ediff-wide-display-p))
ddc90f39
MK
550
551 ;; In multiframe, toolbar is set in ediff-setup-control-frame
bf5d92c5 552 (if (not (ediff-multiframe-setup-p))
ddc90f39 553 (ediff-make-bottom-toolbar)) ; this checks if toolbar is requested
475f9031
KH
554 (goto-char (point-min))
555 (skip-chars-forward ediff-whitespace)))
556
328b4b70
MK
557;; This executes in control buffer and sets auto-save, visited file name, etc,
558;; in the merge buffer
559(defun ediff-arrange-autosave-in-merge-jobs (merge-buffer-file)
560 (if (not ediff-merge-job)
561 ()
562 (if (stringp merge-buffer-file)
563 (setq ediff-autostore-merges t
564 ediff-merge-store-file merge-buffer-file))
565 (if (stringp ediff-merge-store-file)
566 (progn
567 ;; save before leaving ctl buffer
568 (setq merge-buffer-file ediff-merge-store-file)
569 (ediff-with-current-buffer ediff-buffer-C
570 (set-visited-file-name merge-buffer-file))))
571 (ediff-with-current-buffer ediff-buffer-C
572 (setq buffer-offer-save t) ; ask before killing buffer
573 ;; make sure the contents is auto-saved
574 (auto-save-mode 1))
575 ))
475f9031
KH
576
577\f
578;;; Commands for working with Ediff
579
580(defun ediff-update-diffs ()
581 "Recompute difference regions in buffers A, B, and C.
582Buffers are not synchronized with their respective files, so changes done
583to these buffers are not saved at this point---the user can do this later,
584if necessary."
585 (interactive)
651342bc
MK
586 (ediff-barf-if-not-control-buffer)
587 (if (and (ediff-buffer-live-p ediff-ancestor-buffer)
e756eb9f
MK
588 (not
589 (y-or-n-p
590 "Ancestor buffer will not be used. Recompute diffs anyway? ")))
591 (error "Recomputation of differences canceled"))
651342bc 592
e756eb9f
MK
593 (let ((point-A (ediff-with-current-buffer ediff-buffer-A (point)))
594 ;;(point-B (ediff-with-current-buffer ediff-buffer-B (point)))
475f9031 595 (tmp-buffer (get-buffer-create ediff-tmp-buffer))
e756eb9f
MK
596 (buf-A-file-name (buffer-file-name ediff-buffer-A))
597 (buf-B-file-name (buffer-file-name ediff-buffer-B))
598 ;; (null ediff-buffer-C) is no problem, as we later check if
599 ;; ediff-buffer-C is alive
600 (buf-C-file-name (buffer-file-name ediff-buffer-C))
475f9031
KH
601 (overl-A (ediff-get-value-according-to-buffer-type
602 'A ediff-narrow-bounds))
603 (overl-B (ediff-get-value-according-to-buffer-type
604 'B ediff-narrow-bounds))
605 (overl-C (ediff-get-value-according-to-buffer-type
606 'C ediff-narrow-bounds))
607 beg-A end-A beg-B end-B beg-C end-C
608 file-A file-B file-C)
e756eb9f
MK
609
610 (if (stringp buf-A-file-name)
611 (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
612 (if (stringp buf-B-file-name)
613 (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
614 (if (stringp buf-C-file-name)
615 (setq buf-C-file-name (file-name-nondirectory buf-C-file-name)))
616
475f9031
KH
617 (ediff-unselect-and-select-difference -1)
618
619 (setq beg-A (ediff-overlay-start overl-A)
620 beg-B (ediff-overlay-start overl-B)
621 beg-C (ediff-overlay-start overl-C)
622 end-A (ediff-overlay-end overl-A)
623 end-B (ediff-overlay-end overl-B)
624 end-C (ediff-overlay-end overl-C))
625
626 (if ediff-word-mode
627 (progn
628 (ediff-wordify beg-A end-A ediff-buffer-A tmp-buffer)
651342bc 629 (setq file-A (ediff-make-temp-file tmp-buffer "regA"))
475f9031 630 (ediff-wordify beg-B end-B ediff-buffer-B tmp-buffer)
651342bc 631 (setq file-B (ediff-make-temp-file tmp-buffer "regB"))
475f9031
KH
632 (if ediff-3way-job
633 (progn
634 (ediff-wordify beg-C end-C ediff-buffer-C tmp-buffer)
651342bc 635 (setq file-C (ediff-make-temp-file tmp-buffer "regC"))))
475f9031
KH
636 )
637 ;; not word-mode
651342bc
MK
638 (setq file-A (ediff-make-temp-file ediff-buffer-A buf-A-file-name))
639 (setq file-B (ediff-make-temp-file ediff-buffer-B buf-B-file-name))
475f9031 640 (if ediff-3way-job
651342bc 641 (setq file-C (ediff-make-temp-file ediff-buffer-C buf-C-file-name)))
475f9031
KH
642 )
643
644 (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also)
645 (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also)
646 (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also)
651342bc
MK
647 (ediff-clear-diff-vector
648 'ediff-difference-vector-Ancestor 'fine-diffs-also)
649 ;; let them garbage collect. we can't use the ancestor after recomputing
650 ;; the diffs.
651 (setq ediff-difference-vector-Ancestor nil
652 ediff-ancestor-buffer nil
653 ediff-state-of-merge nil)
654
475f9031
KH
655 (setq ediff-killed-diffs-alist nil) ; invalidate saved killed diff regions
656
651342bc 657 ;; In case of merge job, fool it into thinking that it is just doing
475f9031
KH
658 ;; comparison
659 (let ((ediff-setup-diff-regions-function ediff-setup-diff-regions-function)
651342bc
MK
660 (ediff-3way-comparison-job ediff-3way-comparison-job)
661 (ediff-merge-job ediff-merge-job)
662 (ediff-merge-with-ancestor-job ediff-merge-with-ancestor-job)
475f9031
KH
663 (ediff-job-name ediff-job-name))
664 (if ediff-merge-job
665 (setq ediff-setup-diff-regions-function 'ediff-setup-diff-regions3
651342bc
MK
666 ediff-3way-comparison-job t
667 ediff-merge-job nil
668 ediff-merge-with-ancestor-job nil
475f9031
KH
669 ediff-job-name 'ediff-files3))
670 (funcall ediff-setup-diff-regions-function file-A file-B file-C))
671
672 (setq ediff-number-of-differences (length ediff-difference-vector-A))
673 (delete-file file-A)
674 (delete-file file-B)
675 (if file-C
676 (delete-file file-C))
677
678 (if ediff-3way-job
679 (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer))
680
681 (ediff-jump-to-difference (ediff-diff-at-point 'A point-A))
682 (message "")
683 ))
684
685;; Not bound to any key---to dangerous. A user can do it if necessary.
686(defun ediff-revert-buffers-then-recompute-diffs (noconfirm)
687 "Revert buffers A, B and C. Then rerun Ediff on file A and file B."
688 (interactive "P")
651342bc 689 (ediff-barf-if-not-control-buffer)
475f9031
KH
690 (let ((bufA ediff-buffer-A)
691 (bufB ediff-buffer-B)
692 (bufC ediff-buffer-C)
693 (ctl-buf ediff-control-buffer)
651342bc 694 (keep-variants ediff-keep-variants)
475f9031
KH
695 (ancestor-buf ediff-ancestor-buffer)
696 (ancestor-job ediff-merge-with-ancestor-job)
697 (merge ediff-merge-job)
698 (comparison ediff-3way-comparison-job))
e756eb9f 699 (ediff-with-current-buffer bufA
475f9031 700 (revert-buffer t noconfirm))
e756eb9f 701 (ediff-with-current-buffer bufB
475f9031
KH
702 (revert-buffer t noconfirm))
703 ;; this should only be executed in a 3way comparison, not in merge
704 (if comparison
e756eb9f 705 (ediff-with-current-buffer bufC
475f9031
KH
706 (revert-buffer t noconfirm)))
707 (if merge
708 (progn
709 (set-buffer ctl-buf)
651342bc
MK
710 ;; the argument says whether to reverse the meaning of
711 ;; ediff-keep-variants, i.e., ediff-really-quit runs here with
712 ;; variants kept.
713 (ediff-really-quit (not keep-variants))
475f9031
KH
714 (kill-buffer bufC)
715 (if ancestor-job
716 (ediff-merge-buffers-with-ancestor bufA bufB ancestor-buf)
717 (ediff-merge-buffers bufA bufB)))
718 (ediff-update-diffs))))
719
720
721;; optional NO-REHIGHLIGHT says to not rehighlight buffers
722(defun ediff-recenter (&optional no-rehighlight)
723 "Bring the highlighted region of all buffers being compared into view.
724Reestablish the default three-window display."
725 (interactive)
651342bc 726 (ediff-barf-if-not-control-buffer)
475f9031
KH
727 (let (buffer-read-only)
728 (if (and (ediff-buffer-live-p ediff-buffer-A)
729 (ediff-buffer-live-p ediff-buffer-B)
730 (or (not ediff-3way-job)
41d25ad0 731 (ediff-buffer-live-p ediff-buffer-C)))
475f9031
KH
732 (ediff-setup-windows
733 ediff-buffer-A ediff-buffer-B ediff-buffer-C ediff-control-buffer)
734 (or (eq this-command 'ediff-quit)
4ae69eac
MK
735 (message ediff-KILLED-VITAL-BUFFER
736 (beep 1)))
475f9031 737 ))
651342bc 738
475f9031
KH
739 ;; set visibility range appropriate to this invocation of Ediff.
740 (ediff-visible-region)
475f9031 741 ;; raise
41d25ad0 742 (if (and (ediff-window-display-p)
475f9031
KH
743 (symbolp this-command)
744 (symbolp last-command)
745 ;; Either one of the display-changing commands
746 (or (memq this-command
747 '(ediff-recenter
651342bc
MK
748 ediff-dir-action ediff-registry-action
749 ediff-patch-action
475f9031
KH
750 ediff-toggle-wide-display ediff-toggle-multiframe))
751 ;; Or one of the movement cmds and prev cmd was an Ediff cmd
a7acbbe4 752 ;; This avoids raising frames unnecessarily.
475f9031
KH
753 (and (memq this-command
754 '(ediff-next-difference
755 ediff-previous-difference
756 ediff-jump-to-difference
757 ediff-jump-to-difference-at-point))
758 (not (string-match "^ediff-" (symbol-name last-command)))
759 )))
760 (progn
761 (if (window-live-p ediff-window-A)
41d25ad0 762 (raise-frame (window-frame ediff-window-A)))
475f9031 763 (if (window-live-p ediff-window-B)
41d25ad0 764 (raise-frame (window-frame ediff-window-B)))
475f9031 765 (if (window-live-p ediff-window-C)
41d25ad0
KH
766 (raise-frame (window-frame ediff-window-C)))))
767 (if (and (ediff-window-display-p)
768 (frame-live-p ediff-control-frame)
4ae69eac 769 (not ediff-use-long-help-message)
475f9031 770 (not (ediff-frame-iconified-p ediff-control-frame)))
41d25ad0 771 (raise-frame ediff-control-frame))
475f9031
KH
772
773 ;; Redisplay whatever buffers are showing, if there is a selected difference
651342bc
MK
774 (let ((control-frame ediff-control-frame)
775 (control-buf ediff-control-buffer))
475f9031
KH
776 (if (and (ediff-buffer-live-p ediff-buffer-A)
777 (ediff-buffer-live-p ediff-buffer-B)
778 (or (not ediff-3way-job)
bbe6126c 779 (ediff-buffer-live-p ediff-buffer-C)))
475f9031
KH
780 (progn
781 (or no-rehighlight
41d25ad0 782 (ediff-select-difference ediff-current-difference))
651342bc 783
475f9031
KH
784 (ediff-recenter-one-window 'A)
785 (ediff-recenter-one-window 'B)
786 (if ediff-3way-job
787 (ediff-recenter-one-window 'C))
788
e756eb9f 789 (ediff-with-current-buffer control-buf
4ae69eac 790 (ediff-recenter-ancestor) ; check if ancestor is alive
651342bc
MK
791
792 (if (and (ediff-multiframe-setup-p)
4ae69eac 793 (not ediff-use-long-help-message)
651342bc
MK
794 (not (ediff-frame-iconified-p ediff-control-frame)))
795 ;; never grab mouse on quit in this place
796 (ediff-reset-mouse
797 control-frame
798 (eq this-command 'ediff-quit))))
475f9031 799 ))
92c51e07
MK
800
801 (ediff-restore-highlighting)
e756eb9f 802 (ediff-with-current-buffer control-buf (ediff-refresh-mode-lines))
475f9031
KH
803 ))
804
805;; this function returns to the window it was called from
806;; (which was the control window)
807(defun ediff-recenter-one-window (buf-type)
651342bc
MK
808 (if (ediff-valid-difference-p)
809 ;; context must be saved before switching to windows A/B/C
810 (let* ((ctl-wind (selected-window))
811 (shift (ediff-overlay-start
812 (ediff-get-value-according-to-buffer-type
813 buf-type ediff-narrow-bounds)))
814 (job-name ediff-job-name)
815 (control-buf ediff-control-buffer)
e756eb9f
MK
816 (window-name (ediff-get-symbol-from-alist
817 buf-type ediff-window-alist))
651342bc
MK
818 (window (if (window-live-p (symbol-value window-name))
819 (symbol-value window-name))))
820
821 (if (and window ediff-windows-job)
822 (set-window-start window shift))
823 (if window
824 (progn
825 (select-window window)
826 (ediff-deactivate-mark)
827 (ediff-position-region
828 (ediff-get-diff-posn buf-type 'beg nil control-buf)
829 (ediff-get-diff-posn buf-type 'end nil control-buf)
830 (ediff-get-diff-posn buf-type 'beg nil control-buf)
831 job-name
832 )))
833 (select-window ctl-wind)
834 )))
835
836(defun ediff-recenter-ancestor ()
837 ;; do half-hearted job by recentering the ancestor buffer, if it is alive and
838 ;; visible.
839 (if (and (ediff-buffer-live-p ediff-ancestor-buffer)
840 (ediff-valid-difference-p))
841 (let ((window (ediff-get-visible-buffer-window ediff-ancestor-buffer))
842 (ctl-wind (selected-window))
843 (job-name ediff-job-name)
844 (ctl-buf ediff-control-buffer))
e756eb9f 845 (ediff-with-current-buffer ediff-ancestor-buffer
651342bc
MK
846 (goto-char (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf))
847 (if window
848 (progn
849 (select-window window)
850 (ediff-position-region
851 (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf)
852 (ediff-get-diff-posn 'Ancestor 'end nil ctl-buf)
853 (ediff-get-diff-posn 'Ancestor 'beg nil ctl-buf)
854 job-name))))
855 (select-window ctl-wind)
856 )))
475f9031
KH
857
858
859;; This will have to be refined for 3way jobs
860(defun ediff-toggle-split ()
861 "Toggle vertical/horizontal window split.
862Does nothing if file-A and file-B are in different frames."
863 (interactive)
651342bc 864 (ediff-barf-if-not-control-buffer)
475f9031
KH
865 (let* ((wind-A (if (window-live-p ediff-window-A) ediff-window-A))
866 (wind-B (if (window-live-p ediff-window-B) ediff-window-B))
867 (wind-C (if (window-live-p ediff-window-C) ediff-window-C))
41d25ad0
KH
868 (frame-A (if wind-A (window-frame wind-A)))
869 (frame-B (if wind-B (window-frame wind-B)))
870 (frame-C (if wind-C (window-frame wind-C))))
475f9031 871 (if (or (eq frame-A frame-B)
41d25ad0
KH
872 (not (frame-live-p frame-A))
873 (not (frame-live-p frame-B))
475f9031 874 (if ediff-3way-comparison-job
41d25ad0 875 (or (not (frame-live-p frame-C))
475f9031
KH
876 (eq frame-A frame-C) (eq frame-B frame-C))))
877 (setq ediff-split-window-function
878 (if (eq ediff-split-window-function 'split-window-vertically)
879 'split-window-horizontally
880 'split-window-vertically))
881 (message "Buffers being compared are in different frames"))
882 (ediff-recenter 'no-rehighlight)))
883
884(defun ediff-toggle-hilit ()
885 "Switch between highlighting using ASCII flags and highlighting using faces.
886On a dumb terminal, switches between ASCII highlighting and no highlighting."
887 (interactive)
651342bc 888 (ediff-barf-if-not-control-buffer)
4ae69eac 889 (if (not (ediff-has-face-support-p))
475f9031
KH
890 (if (eq ediff-highlighting-style 'ascii)
891 (progn
892 (message "ASCII highlighting flags removed")
893 (ediff-unselect-and-select-difference ediff-current-difference
894 'unselect-only)
895 (setq ediff-highlighting-style 'off))
896 (ediff-unselect-and-select-difference ediff-current-difference
897 'select-only))
898 (ediff-unselect-and-select-difference ediff-current-difference
899 'unselect-only)
900 ;; cycle through highlighting
901 (cond ((and ediff-use-faces ediff-highlight-all-diffs)
902 (message "Unhighlighting unselected difference regions")
903 (setq ediff-highlight-all-diffs nil))
904 (ediff-use-faces
905 (message "Highlighting with ASCII flags")
906 (setq ediff-use-faces nil))
907 (t
908 (message "Re-highlighting all difference regions")
909 (setq ediff-use-faces t
910 ediff-highlight-all-diffs t)))
911
912 (if (and ediff-use-faces ediff-highlight-all-diffs)
92c51e07
MK
913 (ediff-paint-background-regions)
914 (ediff-paint-background-regions 'unhighlight))
475f9031
KH
915
916 (ediff-unselect-and-select-difference
917 ediff-current-difference 'select-only))
475f9031 918 )
92c51e07 919
475f9031
KH
920
921(defun ediff-toggle-autorefine ()
922 "Toggle auto-refine mode."
923 (interactive)
651342bc 924 (ediff-barf-if-not-control-buffer)
475f9031
KH
925 (if ediff-word-mode
926 (error "No fine differences in this mode"))
927 (cond ((eq ediff-auto-refine 'nix)
928 (setq ediff-auto-refine 'on)
929 (ediff-make-fine-diffs ediff-current-difference 'noforce)
930 (message "Auto-refining is ON"))
931 ((eq ediff-auto-refine 'on)
932 (message "Auto-refining is OFF")
933 (setq ediff-auto-refine 'off))
934 (t ;; nix 'em
935 (ediff-set-fine-diff-properties ediff-current-difference 'default)
936 (message "Refinements are HIDDEN")
937 (setq ediff-auto-refine 'nix))
938 ))
651342bc
MK
939
940(defun ediff-show-ancestor ()
941 "Show the ancestor buffer in a suitable window."
942 (interactive)
943 (ediff-recenter)
944 (or (ediff-buffer-live-p ediff-ancestor-buffer)
945 (if ediff-merge-with-ancestor-job
946 (error "Lost connection to ancestor buffer...sorry")
947 (error "Not merging with ancestor")))
948 (let (wind)
949 (cond ((setq wind (ediff-get-visible-buffer-window ediff-ancestor-buffer))
950 (raise-frame (window-frame wind)))
951 (t (set-window-buffer ediff-window-C ediff-ancestor-buffer)))))
475f9031
KH
952
953(defun ediff-make-or-kill-fine-diffs (arg)
954 "Compute fine diffs. With negative prefix arg, kill fine diffs.
955In both cases, operates on the currrent difference region."
956 (interactive "P")
651342bc 957 (ediff-barf-if-not-control-buffer)
475f9031
KH
958 (cond ((eq arg '-)
959 (ediff-clear-fine-differences ediff-current-difference))
960 ((and (numberp arg) (< arg 0))
961 (ediff-clear-fine-differences ediff-current-difference))
962 (t (ediff-make-fine-diffs))))
963
964
965(defun ediff-toggle-help ()
966 "Toggle short/long help message."
967 (interactive)
651342bc 968 (ediff-barf-if-not-control-buffer)
475f9031
KH
969 (let (buffer-read-only)
970 (erase-buffer)
4ae69eac 971 (setq ediff-use-long-help-message (not ediff-use-long-help-message))
475f9031
KH
972 (ediff-set-help-message))
973 ;; remember the icon status of the control frame when the user requested
974 ;; full control message
4ae69eac 975 (if (and ediff-use-long-help-message (ediff-multiframe-setup-p))
475f9031
KH
976 (setq ediff-prefer-iconified-control-frame
977 (ediff-frame-iconified-p ediff-control-frame)))
978
979 (setq ediff-window-config-saved "") ; force redisplay
980 (ediff-recenter 'no-rehighlight))
981
982
41d25ad0
KH
983;; If BUF, this is the buffer to toggle, not current buffer.
984(defun ediff-toggle-read-only (&optional buf)
985 "Toggle read-only in current buffer.
986If buffer is under version control and locked, check it out first.
987If optional argument BUF is specified, toggle read-only in that buffer instead
988of the current buffer."
475f9031 989 (interactive)
651342bc 990 (ediff-barf-if-not-control-buffer)
4ae69eac
MK
991 (let ((ctl-buf (if (null buf) (current-buffer)))
992 (buf-type (ediff-char-to-buftype last-command-char)))
41d25ad0
KH
993 (or buf (ediff-recenter))
994 (or buf
4ae69eac 995 (setq buf (ediff-get-buffer buf-type)))
41d25ad0 996
e756eb9f 997 (ediff-with-current-buffer buf ; eval in buf A/B/C
41d25ad0
KH
998 (let* ((file (buffer-file-name buf))
999 (file-writable (and file
1000 (file-exists-p file)
1001 (file-writable-p file)))
1002 (toggle-ro-cmd (cond (ediff-toggle-read-only-function)
1003 ((ediff-file-checked-out-p file)
1004 'toggle-read-only)
1005 (file-writable 'toggle-read-only)
1006 (t (key-binding "\C-x\C-q")))))
1007 ;; If the file is checked in, make sure we don't make buffer modifiable
1008 ;; without warning the user. The user can fool our checks by making the
1009 ;; buffer non-RO without checking the file out. We regard this as a
1010 ;; user problem.
1011 (if (and (ediff-file-checked-in-p file)
1012 ;; If ctl-buf is null, this means we called this
1013 ;; non-interactively, in which case don't ask questions
1014 ctl-buf)
1015 (cond ((not buffer-read-only)
1016 (setq toggle-ro-cmd 'toggle-read-only))
1017 ((and (or (beep 1) t) ; always beep
1018 (y-or-n-p
1019 (format
1020 "File %s is under version control. Check it out? "
651342bc 1021 (ediff-abbreviate-file-name file))))
41d25ad0
KH
1022 ;; if we checked the file out, we should also change the
1023 ;; original state of buffer-read-only to nil. If we don't
1024 ;; do this, the mode line will show %%, since the file was
1025 ;; RO before ediff started, so the user will think the file
1026 ;; is checked in.
e756eb9f 1027 (ediff-with-current-buffer ctl-buf
41d25ad0 1028 (ediff-change-saved-variable
4ae69eac 1029 'buffer-read-only nil buf-type)))
41d25ad0
KH
1030 (t
1031 (setq toggle-ro-cmd 'toggle-read-only)
1032 (beep 1) (beep 1)
1033 (message
bf5d92c5 1034 "Boy, this is risky! Don't modify this file...")
651342bc 1035 (sit-for 3)))) ; let the user see the warning
41d25ad0
KH
1036 (if (and toggle-ro-cmd
1037 (string-match "toggle-read-only" (symbol-name toggle-ro-cmd)))
1038 (save-excursion
1039 (save-window-excursion
bf5d92c5 1040 (select-window (ediff-get-visible-buffer-window buf))
41d25ad0
KH
1041 (command-execute toggle-ro-cmd)))
1042 (error "Don't know how to toggle read-only in buffer %S" buf))
1043
1044 ;; Check if we made the current buffer updatable, but its file is RO.
1045 ;; Signal a warning in this case.
1046 (if (and file (not buffer-read-only)
1047 (eq this-command 'ediff-toggle-read-only)
1048 (file-exists-p file)
1049 (not (file-writable-p file)))
1050 (message "Warning: file %s is read-only"
651342bc 1051 (ediff-abbreviate-file-name file) (beep 1)))
41d25ad0 1052 ))))
41d25ad0 1053
bf5d92c5
MK
1054;; checkout if visited file is checked in
1055(defun ediff-maybe-checkout (buf)
1056 (let ((file (buffer-file-name buf))
1057 (checkout-function (key-binding "\C-x\C-q")))
1058 (if (and (ediff-file-checked-in-p file)
1059 (or (beep 1) t)
1060 (y-or-n-p
1061 (format
1062 "File %s is under version control. Check it out? "
1063 (ediff-abbreviate-file-name file))))
e756eb9f 1064 (ediff-with-current-buffer buf
bf5d92c5
MK
1065 (command-execute checkout-function)))))
1066
1067
1068;; This is a simple-minded check for whether a file is under version control.
41d25ad0
KH
1069;; If file,v exists but file doesn't, this file is considered to be not checked
1070;; in and not checked out for the purpose of patching (since patch won't be
1071;; able to read such a file anyway).
1072;; FILE is a string representing file name
bf5d92c5
MK
1073(defun ediff-file-under-version-control (file)
1074 (let* ((filedir (file-name-directory file))
1075 (file-nondir (file-name-nondirectory file))
1076 (trial (concat file-nondir ",v"))
1077 (full-trial (concat filedir trial))
1078 (full-rcs-trial (concat filedir "RCS/" trial)))
1079 (and (stringp file)
1080 (file-exists-p file)
1081 (or
1082 (and
1083 (file-exists-p full-trial)
1084 ;; in FAT FS, `file,v' and `file' may turn out to be the same!
1085 ;; don't be fooled by this!
1086 (not (equal (file-attributes file)
1087 (file-attributes full-trial))))
1088 ;; check if a version is in RCS/ directory
1089 (file-exists-p full-rcs-trial)))
4ae69eac 1090 ))
bf5d92c5
MK
1091
1092(defun ediff-file-checked-out-p (file)
1093 (and (ediff-file-under-version-control file)
1094 (file-writable-p file)))
4ae69eac 1095(defun ediff-file-checked-in-p (file)
bf5d92c5
MK
1096 (and (ediff-file-under-version-control file)
1097 (not (file-writable-p file))))
475f9031
KH
1098
1099(defun ediff-swap-buffers ()
1100 "Rotate the display of buffers A, B, and C."
1101 (interactive)
651342bc 1102 (ediff-barf-if-not-control-buffer)
475f9031
KH
1103 (if (and (window-live-p ediff-window-A) (window-live-p ediff-window-B))
1104 (let ((buf ediff-buffer-A)
41d25ad0 1105 (values ediff-buffer-values-orig-A)
475f9031
KH
1106 (diff-vec ediff-difference-vector-A)
1107 (hide-regexp ediff-regexp-hide-A)
1108 (focus-regexp ediff-regexp-focus-A)
1109 (wide-visibility-p (eq ediff-visible-bounds ediff-wide-bounds))
4ae69eac 1110 (overlay (if (ediff-has-face-support-p)
41d25ad0 1111 ediff-current-diff-overlay-A)))
475f9031
KH
1112 (if ediff-3way-comparison-job
1113 (progn
1114 (set-window-buffer ediff-window-A ediff-buffer-C)
1115 (set-window-buffer ediff-window-B ediff-buffer-A)
1116 (set-window-buffer ediff-window-C ediff-buffer-B)
1117 )
1118 (set-window-buffer ediff-window-A ediff-buffer-B)
1119 (set-window-buffer ediff-window-B ediff-buffer-A))
1120 ;; swap diff buffers
1121 (if ediff-3way-comparison-job
1122 (setq ediff-buffer-A ediff-buffer-C
1123 ediff-buffer-C ediff-buffer-B
1124 ediff-buffer-B buf)
1125 (setq ediff-buffer-A ediff-buffer-B
1126 ediff-buffer-B buf))
1127
1128 ;; swap saved buffer characteristics
1129 (if ediff-3way-comparison-job
41d25ad0
KH
1130 (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-C
1131 ediff-buffer-values-orig-C ediff-buffer-values-orig-B
1132 ediff-buffer-values-orig-B values)
1133 (setq ediff-buffer-values-orig-A ediff-buffer-values-orig-B
1134 ediff-buffer-values-orig-B values))
475f9031
KH
1135
1136 ;; swap diff vectors
1137 (if ediff-3way-comparison-job
1138 (setq ediff-difference-vector-A ediff-difference-vector-C
1139 ediff-difference-vector-C ediff-difference-vector-B
1140 ediff-difference-vector-B diff-vec)
1141 (setq ediff-difference-vector-A ediff-difference-vector-B
1142 ediff-difference-vector-B diff-vec))
1143
1144 ;; swap hide/focus regexp
1145 (if ediff-3way-comparison-job
1146 (setq ediff-regexp-hide-A ediff-regexp-hide-C
1147 ediff-regexp-hide-C ediff-regexp-hide-B
1148 ediff-regexp-hide-B hide-regexp
1149 ediff-regexp-focus-A ediff-regexp-focus-C
1150 ediff-regexp-focus-C ediff-regexp-focus-B
1151 ediff-regexp-focus-B focus-regexp)
1152 (setq ediff-regexp-hide-A ediff-regexp-hide-B
1153 ediff-regexp-hide-B hide-regexp
1154 ediff-regexp-focus-A ediff-regexp-focus-B
1155 ediff-regexp-focus-B focus-regexp))
1156
1157 ;; The following is needed for XEmacs, since there one can't move
1158 ;; overlay to another buffer. In Emacs, this swap is redundant.
4ae69eac 1159 (if (ediff-has-face-support-p)
475f9031
KH
1160 (if ediff-3way-comparison-job
1161 (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-C
1162 ediff-current-diff-overlay-C ediff-current-diff-overlay-B
1163 ediff-current-diff-overlay-B overlay)
1164 (setq ediff-current-diff-overlay-A ediff-current-diff-overlay-B
1165 ediff-current-diff-overlay-B overlay)))
1166
1167 ;; swap wide bounds
1168 (setq ediff-wide-bounds
1169 (cond (ediff-3way-comparison-job
1170 (list (nth 2 ediff-wide-bounds)
1171 (nth 0 ediff-wide-bounds)
1172 (nth 1 ediff-wide-bounds)))
1173 (ediff-3way-job
1174 (list (nth 1 ediff-wide-bounds)
1175 (nth 0 ediff-wide-bounds)
1176 (nth 2 ediff-wide-bounds)))
1177 (t
1178 (list (nth 1 ediff-wide-bounds)
1179 (nth 0 ediff-wide-bounds)))))
1180 ;; swap narrow bounds
1181 (setq ediff-narrow-bounds
1182 (cond (ediff-3way-comparison-job
1183 (list (nth 2 ediff-narrow-bounds)
1184 (nth 0 ediff-narrow-bounds)
1185 (nth 1 ediff-narrow-bounds)))
1186 (ediff-3way-job
1187 (list (nth 1 ediff-narrow-bounds)
1188 (nth 0 ediff-narrow-bounds)
1189 (nth 2 ediff-narrow-bounds)))
1190 (t
1191 (list (nth 1 ediff-narrow-bounds)
1192 (nth 0 ediff-narrow-bounds)))))
1193 (if wide-visibility-p
1194 (setq ediff-visible-bounds ediff-wide-bounds)
1195 (setq ediff-visible-bounds ediff-narrow-bounds))
1196 ))
1197 (if ediff-3way-job
1198 (ediff-set-state-of-all-diffs-in-all-buffers ediff-control-buffer))
1199 (ediff-recenter 'no-rehighlight)
1200 )
1201
1202
1203(defun ediff-toggle-wide-display ()
1204 "Toggle wide/regular display.
1205This is especially useful when comparing buffers side-by-side."
1206 (interactive)
651342bc 1207 (ediff-barf-if-not-control-buffer)
41d25ad0
KH
1208 (or (ediff-window-display-p)
1209 (error "%sEmacs is not running as a window application"
1210 (if ediff-emacs-p "" "X")))
475f9031
KH
1211 (ediff-recenter 'no-rehighlight) ; make sure buffs are displayed in windows
1212 (let ((ctl-buf ediff-control-buffer))
1213 (setq ediff-wide-display-p (not ediff-wide-display-p))
1214 (if (not ediff-wide-display-p)
e756eb9f 1215 (ediff-with-current-buffer ctl-buf
41d25ad0 1216 (modify-frame-parameters
475f9031 1217 ediff-wide-display-frame ediff-wide-display-orig-parameters)
651342bc 1218 ;;(sit-for (if ediff-xemacs-p 0.4 0))
475f9031
KH
1219 ;; restore control buf, since ctl window may have been deleted
1220 ;; during resizing
1221 (set-buffer ctl-buf)
1222 (setq ediff-wide-display-orig-parameters nil
1223 ediff-window-B nil) ; force update of window config
1224 (ediff-recenter 'no-rehighlight))
1225 (funcall ediff-make-wide-display-function)
651342bc 1226 ;;(sit-for (if ediff-xemacs-p 0.4 0))
e756eb9f 1227 (ediff-with-current-buffer ctl-buf
475f9031
KH
1228 (setq ediff-window-B nil) ; force update of window config
1229 (ediff-recenter 'no-rehighlight)))))
1230
bf5d92c5 1231;;;###autoload
475f9031 1232(defun ediff-toggle-multiframe ()
ddc90f39
MK
1233 "Switch from multiframe display to single-frame display and back.
1234To change the default, set the variable `ediff-window-setup-function',
bbe6126c 1235which see."
475f9031 1236 (interactive)
ddc90f39
MK
1237 (let (window-setup-func)
1238 (or (ediff-window-display-p)
1239 (error "%sEmacs is not running as a window application"
1240 (if ediff-emacs-p "" "X")))
bf5d92c5 1241
475f9031 1242 (cond ((eq ediff-window-setup-function 'ediff-setup-windows-multiframe)
ddc90f39 1243 (setq window-setup-func 'ediff-setup-windows-plain))
475f9031 1244 ((eq ediff-window-setup-function 'ediff-setup-windows-plain)
bf5d92c5
MK
1245 (if (ediff-in-control-buffer-p)
1246 (ediff-kill-bottom-toolbar))
ddc90f39
MK
1247 (setq window-setup-func 'ediff-setup-windows-multiframe)))
1248
1249 ;; change default
1250 (setq-default ediff-window-setup-function window-setup-func)
1251 ;; change in all active ediff sessions
1252 (mapcar (function (lambda(buf)
e756eb9f 1253 (ediff-with-current-buffer buf
ddc90f39
MK
1254 (setq ediff-window-setup-function window-setup-func
1255 ediff-window-B nil))))
1256 ediff-session-registry)
bf5d92c5 1257 (if (ediff-in-control-buffer-p)
ddc90f39
MK
1258 (ediff-recenter 'no-rehighlight))))
1259
1260
1261;;;###autoload
1262(defun ediff-toggle-use-toolbar ()
1263 "Enable or disable Ediff toolbar.
1264Works only in versions of Emacs that support toolbars.
1265To change the default, set the variable `ediff-use-toolbar-p', which see."
1266 (interactive)
1267 (if (featurep 'ediff-tbar)
bf5d92c5 1268 (progn
ddc90f39
MK
1269 (or (ediff-window-display-p)
1270 (error "%sEmacs is not running as a window application"
1271 (if ediff-emacs-p "" "X")))
1272 (if (ediff-use-toolbar-p)
1273 (ediff-kill-bottom-toolbar))
1274 ;; do this only after killing the toolbar
1275 (setq ediff-use-toolbar-p (not ediff-use-toolbar-p))
1276
1277 (mapcar (function (lambda(buf)
e756eb9f 1278 (ediff-with-current-buffer buf
ddc90f39
MK
1279 ;; force redisplay
1280 (setq ediff-window-config-saved "")
1281 )))
1282 ediff-session-registry)
1283 (if (ediff-in-control-buffer-p)
1284 (ediff-recenter 'no-rehighlight)))))
1285
bf5d92c5
MK
1286
1287;; if was using toolbar, kill it
1288(defun ediff-kill-bottom-toolbar ()
1289 ;; Using ctl-buffer or ediff-control-window for LOCALE does not
1290 ;; work properly in XEmacs 19.14: we have to use
1291 ;;(selected-frame).
1292 ;; The problem with this is that any previous bottom-toolbar
1293 ;; will not re-appear after our cleanup here. Is there a way
1294 ;; to do "push" and "pop" toolbars ? --marcpa
1295 (if (ediff-use-toolbar-p)
1296 (progn
1297 (set-specifier bottom-toolbar (list (selected-frame) nil))
1298 (set-specifier bottom-toolbar-visible-p (list (selected-frame) nil)))))
1299
ddc90f39
MK
1300;; If wants to use toolbar, make it.
1301;; If not, zero the toolbar for XEmacs.
1302;; Do nothing for Emacs.
1303(defun ediff-make-bottom-toolbar (&optional frame)
1304 (if (ediff-window-display-p)
bf5d92c5 1305 (progn
ddc90f39
MK
1306 (setq frame (or frame (selected-frame)))
1307 (cond ((ediff-use-toolbar-p) ; this checks for XEmacs
1308 (set-specifier
1309 bottom-toolbar
1310 (list frame (if (ediff-3way-comparison-job)
1311 ediff-toolbar-3way ediff-toolbar)))
1312 (set-specifier bottom-toolbar-visible-p (list frame t))
1313 (set-specifier bottom-toolbar-height
1314 (list frame ediff-toolbar-height)))
1315 (ediff-xemacs-p
1316 (set-specifier bottom-toolbar-height (list frame 0)))
1317 ))
1318 ))
475f9031
KH
1319
1320;; Merging
1321
1322(defun ediff-toggle-show-clashes-only ()
1323 "Toggle the mode where only the regions where both buffers differ with the ancestor are shown."
1324 (interactive)
651342bc 1325 (ediff-barf-if-not-control-buffer)
475f9031
KH
1326 (if (not ediff-merge-with-ancestor-job)
1327 (error "This command makes sense only when merging with an ancestor"))
1328 (setq ediff-show-clashes-only (not ediff-show-clashes-only))
1329 (if ediff-show-clashes-only
1330 (message "Focus on regions where both buffers differ from the ancestor")
1331 (message "Canceling focus on regions where changes clash")))
1332
1333;; Widening/narrowing
1334
1335(defun ediff-toggle-narrow-region ()
1336 "Toggle narrowing in buffers A, B, and C.
1337Used in ediff-windows/regions only."
1338 (interactive)
1339 (if (eq ediff-buffer-A ediff-buffer-B)
4ae69eac 1340 (error ediff-NO-DIFFERENCES))
475f9031
KH
1341 (if (eq ediff-visible-bounds ediff-wide-bounds)
1342 (setq ediff-visible-bounds ediff-narrow-bounds)
1343 (setq ediff-visible-bounds ediff-wide-bounds))
1344 (ediff-recenter 'no-rehighlight))
1345
1346;; Narrow bufs A/B/C to ediff-visible-bounds. If this is currently set to
1347;; ediff-wide-bounds, then this actually widens.
41d25ad0
KH
1348;; This function does nothing if job-name is not
1349;; ediff-regions-wordwise/linewise or ediff-windows-wordwise/linewise.
475f9031
KH
1350;; Does nothing if buffer-A = buffer-B since we can't narrow
1351;; to two different regions in one buffer.
1352(defun ediff-visible-region ()
1353 (if (or (eq ediff-buffer-A ediff-buffer-B)
1354 (eq ediff-buffer-A ediff-buffer-C)
1355 (eq ediff-buffer-C ediff-buffer-B))
1356 ()
1357 ;; If ediff-*-regions/windows, ediff-visible-bounds is already set
1358 ;; Otherwise, always use full range.
41d25ad0 1359 (if (not ediff-narrow-job)
475f9031
KH
1360 (setq ediff-visible-bounds ediff-wide-bounds))
1361 (let ((overl-A (ediff-get-value-according-to-buffer-type
1362 'A ediff-visible-bounds))
1363 (overl-B (ediff-get-value-according-to-buffer-type
1364 'B ediff-visible-bounds))
1365 (overl-C (ediff-get-value-according-to-buffer-type
1366 'C ediff-visible-bounds))
1367 )
e756eb9f 1368 (ediff-with-current-buffer ediff-buffer-A
328b4b70
MK
1369 (if (ediff-overlay-buffer overl-A)
1370 (narrow-to-region
1371 (ediff-overlay-start overl-A) (ediff-overlay-end overl-A))))
e756eb9f 1372 (ediff-with-current-buffer ediff-buffer-B
328b4b70
MK
1373 (if (ediff-overlay-buffer overl-B)
1374 (narrow-to-region
1375 (ediff-overlay-start overl-B) (ediff-overlay-end overl-B))))
475f9031 1376
328b4b70 1377 (if (and ediff-3way-job (ediff-overlay-buffer overl-C))
e756eb9f 1378 (ediff-with-current-buffer ediff-buffer-C
475f9031
KH
1379 (narrow-to-region
1380 (ediff-overlay-start overl-C) (ediff-overlay-end overl-C))))
1381 )))
1382
1383
1384;; Window scrolling operations
1385
1386;; Performs some operation on the two file windows (if they are showing).
1387;; Traps all errors on the operation in windows A/B/C.
1388;; Usually, errors come from scrolling off the
1389;; beginning or end of the buffer, and this gives error messages.
1390(defun ediff-operate-on-windows (operation arg)
1391
1392 ;; make sure windows aren't dead
1393 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1394 (ediff-recenter 'no-rehighlight))
1395 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1396 (ediff-buffer-live-p ediff-buffer-B)
1397 (or (not ediff-3way-job) ediff-buffer-C)
1398 ))
4ae69eac 1399 (error ediff-KILLED-VITAL-BUFFER))
475f9031
KH
1400
1401 (let* ((wind (selected-window))
1402 (wind-A ediff-window-A)
1403 (wind-B ediff-window-B)
1404 (wind-C ediff-window-C)
651342bc
MK
1405 (coefA (ediff-get-region-size-coefficient 'A operation))
1406 (coefB (ediff-get-region-size-coefficient 'B operation))
1407 (three-way ediff-3way-job)
1408 (coefC (if three-way
1409 (ediff-get-region-size-coefficient 'C operation))))
475f9031
KH
1410
1411 (select-window wind-A)
1412 (condition-case nil
651342bc 1413 (funcall operation (round (* coefA arg)))
475f9031
KH
1414 (error))
1415 (select-window wind-B)
1416 (condition-case nil
651342bc 1417 (funcall operation (round (* coefB arg)))
475f9031
KH
1418 (error))
1419 (if three-way
1420 (progn
1421 (select-window wind-C)
1422 (condition-case nil
651342bc 1423 (funcall operation (round (* coefC arg)))
475f9031 1424 (error))))
475f9031
KH
1425 (select-window wind)))
1426
1427(defun ediff-scroll-vertically (&optional arg)
1428 "Vertically scroll buffers A, B \(and C if appropriate\).
1429With optional argument ARG, scroll ARG lines; otherwise scroll by nearly
4ae69eac 1430the one half of the height of window-A."
475f9031 1431 (interactive "P")
651342bc 1432 (ediff-barf-if-not-control-buffer)
475f9031
KH
1433
1434 ;; make sure windows aren't dead
1435 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1436 (ediff-recenter 'no-rehighlight))
1437 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1438 (ediff-buffer-live-p ediff-buffer-B)
1439 (or (not ediff-3way-job)
1440 (ediff-buffer-live-p ediff-buffer-C))
1441 ))
4ae69eac 1442 (error ediff-KILLED-VITAL-BUFFER))
475f9031
KH
1443
1444 (ediff-operate-on-windows
1445 (if (memq last-command-char '(?v ?\C-v))
1446 'scroll-up
1447 'scroll-down)
1448 ;; calculate argument to scroll-up/down
1449 ;; if there is an explicit argument
1450 (if (and arg (not (equal arg '-)))
1451 ;; use it
1452 (prefix-numeric-value arg)
1453 ;; if not, see if we can determine a default amount (the window height)
651342bc 1454 (let (default-amount)
475f9031 1455 (setq default-amount
651342bc
MK
1456 (- (/ (min (window-height ediff-window-A)
1457 (window-height ediff-window-B)
1458 (if ediff-3way-job
1459 (window-height ediff-window-C)
1460 500)) ; some large number
1461 2)
475f9031
KH
1462 1 next-screen-context-lines))
1463 ;; window found
1464 (if arg
1465 ;; C-u as argument means half of default amount
1466 (/ default-amount 2)
1467 ;; no argument means default amount
1468 default-amount)))))
1469
1470
1471(defun ediff-scroll-horizontally (&optional arg)
1472 "Horizontally scroll buffers A, B \(and C if appropriate\).
1473If an argument is given, that is how many columns are scrolled, else nearly
1474the width of the A/B/C windows."
1475 (interactive "P")
651342bc 1476 (ediff-barf-if-not-control-buffer)
475f9031
KH
1477
1478 ;; make sure windows aren't dead
1479 (if (not (and (window-live-p ediff-window-A) (window-live-p ediff-window-B)))
1480 (ediff-recenter 'no-rehighlight))
1481 (if (not (and (ediff-buffer-live-p ediff-buffer-A)
1482 (ediff-buffer-live-p ediff-buffer-B)
1483 (or (not ediff-3way-job)
1484 (ediff-buffer-live-p ediff-buffer-C))
1485 ))
4ae69eac 1486 (error ediff-KILLED-VITAL-BUFFER))
475f9031
KH
1487
1488 (ediff-operate-on-windows
1489 (if (= last-command-char ?<)
1490 'scroll-left
1491 'scroll-right)
1492 ;; calculate argument to scroll-left/right
1493 ;; if there is an explicit argument
1494 (if (and arg (not (equal arg '-)))
1495 ;; use it
1496 (prefix-numeric-value arg)
1497 ;; if not, see if we can determine a default amount
1498 ;; (half the window width)
1499 (if (null ediff-control-window)
1500 ;; no control window, use nil
1501 nil
1502 (let ((default-amount
1503 (- (/ (min (window-width ediff-window-A)
1504 (window-width ediff-window-B)
1505 (if ediff-3way-comparison-job
1506 (window-width ediff-window-C)
1507 500) ; some large number
1508 )
1509 2)
1510 3)))
1511 ;; window found
1512 (if arg
1513 ;; C-u as argument means half of default amount
1514 (/ default-amount 2)
1515 ;; no argument means default amount
1516 default-amount))))))
1517
1518
1519;;BEG, END show the region to be positioned.
bbe6126c 1520;;JOB-NAME holds ediff-job-name. The ediff-windows job positions regions
475f9031
KH
1521;;differently.
1522(defun ediff-position-region (beg end pos job-name)
1523 (if (> end (point-max))
1524 (setq end (point-max)))
41d25ad0 1525 (if ediff-windows-job
475f9031
KH
1526 (if (pos-visible-in-window-p end)
1527 () ; do nothing, wind is already positioned
1528 ;; at this point, windows are positioned at the beginning of the
1529 ;; file regions (not diff-regions) being compared.
1530 (save-excursion
1531 (move-to-window-line (- (window-height) 2))
1532 (let ((amount (+ 2 (count-lines (point) end))))
1533 (scroll-up amount))))
1534 (set-window-start (selected-window) beg)
1535 (if (pos-visible-in-window-p end)
1536 ;; Determine the number of lines that the region occupies
41d25ad0
KH
1537 (let ((lines 0)
1538 (prev-point 0))
1539 (while ( and (> end (progn
1540 (move-to-window-line lines)
1541 (point)))
1542 ;; `end' may be beyond the window bottom, so check
a7acbbe4 1543 ;; that we are making progress
41d25ad0
KH
1544 (< prev-point (point)))
1545 (setq prev-point (point))
475f9031
KH
1546 (setq lines (1+ lines)))
1547 ;; And position the beginning on the right line
1548 (goto-char beg)
1549 (recenter (/ (1+ (max (- (1- (window-height (selected-window)))
1550 lines)
1551 1)
1552 )
1553 2))))
1554 (goto-char pos)
1555 ))
1556
651342bc
MK
1557;; get number of lines from window start to region end
1558(defun ediff-get-lines-to-region-end (buf-type &optional n ctl-buf)
1559 (or n (setq n ediff-current-difference))
1560 (or ctl-buf (setq ctl-buf ediff-control-buffer))
e756eb9f 1561 (ediff-with-current-buffer ctl-buf
651342bc 1562 (let* ((buf (ediff-get-buffer buf-type))
e756eb9f
MK
1563 (wind (eval (ediff-get-symbol-from-alist
1564 buf-type ediff-window-alist)))
651342bc
MK
1565 (beg (window-start wind))
1566 (end (ediff-get-diff-posn buf-type 'end))
1567 lines)
e756eb9f 1568 (ediff-with-current-buffer buf
651342bc
MK
1569 (if (< beg end)
1570 (setq lines (count-lines beg end))
1571 (setq lines 0))
1572 lines
1573 ))))
1574
1575;; get number of lines from window end to region start
1576(defun ediff-get-lines-to-region-start (buf-type &optional n ctl-buf)
1577 (or n (setq n ediff-current-difference))
1578 (or ctl-buf (setq ctl-buf ediff-control-buffer))
e756eb9f 1579 (ediff-with-current-buffer ctl-buf
651342bc 1580 (let* ((buf (ediff-get-buffer buf-type))
e756eb9f
MK
1581 (wind (eval (ediff-get-symbol-from-alist
1582 buf-type ediff-window-alist)))
651342bc
MK
1583 (end (window-end wind))
1584 (beg (ediff-get-diff-posn buf-type 'beg)))
e756eb9f 1585 (ediff-with-current-buffer buf
651342bc
MK
1586 (if (< beg end) (count-lines beg end) 0))
1587 )))
1588
1589
bbe6126c
MK
1590;; region size coefficient is a coefficient by which to adjust scrolling
1591;; up/down of the window displaying buffer of type BUFTYPE.
1592;; The purpose of this coefficient is to make the windows scroll in sync, so
1593;; that it won't happen that one diff region is scrolled off while the other is
1594;; still seen.
1595;;
1596;; If the difference region is invalid, the coefficient is 1
651342bc 1597(defun ediff-get-region-size-coefficient (buf-type op &optional n ctl-buf)
e756eb9f 1598 (ediff-with-current-buffer (or ctl-buf ediff-control-buffer)
bbe6126c
MK
1599 (if (ediff-valid-difference-p n)
1600 (let* ((func (cond ((eq op 'scroll-down)
1601 'ediff-get-lines-to-region-start)
1602 ((eq op 'scroll-up)
1603 'ediff-get-lines-to-region-end)
1604 (t '(lambda (a b c) 0))))
1605 (max-lines (max (funcall func 'A n ctl-buf)
1606 (funcall func 'B n ctl-buf)
1607 (if (ediff-buffer-live-p ediff-buffer-C)
1608 (funcall func 'C n ctl-buf)
1609 0))))
1610 ;; this covers the horizontal coefficient as well:
1611 ;; if max-lines = 0 then coef = 1
1612 (if (> max-lines 0)
1613 (/ (+ (funcall func buf-type n ctl-buf) 0.0)
1614 (+ max-lines 0.0))
1615 1))
1616 1)))
651342bc 1617
475f9031
KH
1618
1619(defun ediff-next-difference (&optional arg)
1620 "Advance to the next difference.
bbe6126c
MK
1621With a prefix argument, go forward that many differences."
1622 (interactive "p")
651342bc 1623 (ediff-barf-if-not-control-buffer)
475f9031
KH
1624 (if (< ediff-current-difference ediff-number-of-differences)
1625 (let ((n (min ediff-number-of-differences
bbe6126c 1626 (+ ediff-current-difference arg)))
8e41a31c 1627 non-clash-skip regexp-skip)
475f9031 1628
ddc90f39 1629 (ediff-visible-region)
475f9031
KH
1630 (or (>= n ediff-number-of-differences)
1631 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
8e41a31c
MK
1632 ;; this won't exec if regexp-skip is t
1633 (setq non-clash-skip (ediff-merge-region-is-non-clash n))
475f9031
KH
1634 (ediff-install-fine-diff-if-necessary n))
1635 (while (and (< n ediff-number-of-differences)
1636 (or
1637 ;; regexp skip
1638 regexp-skip
1639 ;; skip clashes, if necessary
8e41a31c 1640 non-clash-skip
475f9031
KH
1641 ;; skip difference regions that differ in white space
1642 (and ediff-ignore-similar-regions
ddc90f39 1643 (eq (ediff-no-fine-diffs-p n) t))))
475f9031
KH
1644 (setq n (1+ n))
1645 (if (= 0 (mod n 20))
1646 (message "Skipped over region %d and counting ..." n))
1647 (or (>= n ediff-number-of-differences)
1648 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
8e41a31c
MK
1649 ;; this won't exec if regexp-skip is t
1650 (setq non-clash-skip (ediff-merge-region-is-non-clash n))
475f9031
KH
1651 (ediff-install-fine-diff-if-necessary n))
1652 )
41d25ad0 1653 (message "")
475f9031
KH
1654 (ediff-unselect-and-select-difference n)
1655 ) ; let
1656 (ediff-visible-region)
1657 (error "At end of the difference list")))
1658
1659(defun ediff-previous-difference (&optional arg)
1660 "Go to the previous difference.
1661With a prefix argument, go back that many differences."
bbe6126c 1662 (interactive "p")
651342bc 1663 (ediff-barf-if-not-control-buffer)
475f9031 1664 (if (> ediff-current-difference -1)
bbe6126c 1665 (let ((n (max -1 (- ediff-current-difference arg)))
8e41a31c 1666 non-clash-skip regexp-skip)
475f9031 1667
ddc90f39 1668 (ediff-visible-region)
475f9031
KH
1669 (or (< n 0)
1670 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
8e41a31c
MK
1671 ;; this won't exec if regexp-skip is t
1672 (setq non-clash-skip (ediff-merge-region-is-non-clash n))
475f9031
KH
1673 (ediff-install-fine-diff-if-necessary n))
1674 (while (and (> n -1)
1675 (or
1676 ;; regexp skip
1677 regexp-skip
1678 ;; skip clashes, if necessary
8e41a31c 1679 non-clash-skip
475f9031
KH
1680 ;; skip difference regions that differ in white space
1681 (and ediff-ignore-similar-regions
ddc90f39 1682 (eq (ediff-no-fine-diffs-p n) t))))
475f9031
KH
1683 (if (= 0 (mod (1+ n) 20))
1684 (message "Skipped over region %d and counting ..." (1+ n)))
1685 (setq n (1- n))
1686 (or (< n 0)
1687 (setq regexp-skip (funcall ediff-skip-diff-region-function n))
8e41a31c
MK
1688 ;; this won't exec if regexp-skip is t
1689 (setq non-clash-skip (ediff-merge-region-is-non-clash n))
475f9031
KH
1690 (ediff-install-fine-diff-if-necessary n))
1691 )
41d25ad0 1692 (message "")
475f9031
KH
1693 (ediff-unselect-and-select-difference n)
1694 ) ; let
1695 (ediff-visible-region)
1696 (error "At beginning of the difference list")))
1697
bbe6126c
MK
1698;; The diff number is as perceived by the user (i.e., 1+ the internal
1699;; representation)
475f9031 1700(defun ediff-jump-to-difference (difference-number)
bbe6126c
MK
1701 "Go to the difference specified as a prefix argument.
1702If the prefix is negative, count differences from the end."
475f9031 1703 (interactive "p")
651342bc 1704 (ediff-barf-if-not-control-buffer)
bbe6126c
MK
1705 (setq difference-number
1706 (cond ((< difference-number 0)
1707 (+ ediff-number-of-differences difference-number))
1708 ((> difference-number 0) (1- difference-number))
1709 (t -1)))
1710 ;; -1 is allowed by ediff-unselect-and-select-difference --- it is the
1711 ;; position before the first one.
41d25ad0 1712 (if (and (>= difference-number -1)
bbe6126c 1713 (<= difference-number ediff-number-of-differences))
41d25ad0 1714 (ediff-unselect-and-select-difference difference-number)
bbe6126c
MK
1715 (error ediff-BAD-DIFF-NUMBER
1716 this-command (1+ difference-number) ediff-number-of-differences)))
475f9031 1717
bbe6126c 1718(defun ediff-jump-to-difference-at-point (arg)
475f9031 1719 "Go to difference closest to the point in buffer A, B, or C.
bbe6126c
MK
1720The buffer depends on last command character \(a, b, or c\) that invoked this
1721command. For instance, if the command was `ga' then the point value in buffer A
1722is used.
1723With a prefix argument, synchronize all files around the current point position
1724in the specified buffer."
1725 (interactive "P")
651342bc 1726 (ediff-barf-if-not-control-buffer)
bbe6126c
MK
1727 (let* ((buf-type (ediff-char-to-buftype last-command-char))
1728 (buffer (ediff-get-buffer buf-type))
e756eb9f 1729 (pt (ediff-with-current-buffer buffer (point)))
bbe6126c
MK
1730 (diff-no (ediff-diff-at-point buf-type nil (if arg 'after)))
1731 (past-last-diff (< ediff-number-of-differences diff-no))
1732 (beg (if past-last-diff
e756eb9f 1733 (ediff-with-current-buffer buffer (point-max))
bbe6126c
MK
1734 (ediff-get-diff-posn buf-type 'beg (1- diff-no))))
1735 ctl-wind wind-A wind-B wind-C
1736 shift)
1737 (if past-last-diff
1738 (ediff-jump-to-difference -1)
1739 (ediff-jump-to-difference diff-no))
1740 (setq ctl-wind (selected-window)
1741 wind-A ediff-window-A
1742 wind-B ediff-window-B
1743 wind-C ediff-window-C)
1744 (if arg
1745 (progn
e756eb9f 1746 (ediff-with-current-buffer buffer
bbe6126c
MK
1747 (setq shift (- beg pt)))
1748 (select-window wind-A)
1749 (if past-last-diff (goto-char (point-max)))
1750 (condition-case nil
1751 (backward-char shift) ; noerror, if beginning of buffer
1752 (error))
1753 (recenter)
1754 (select-window wind-B)
1755 (if past-last-diff (goto-char (point-max)))
1756 (condition-case nil
1757 (backward-char shift) ; noerror, if beginning of buffer
1758 (error))
1759 (recenter)
1760 (if (window-live-p wind-C)
1761 (progn
1762 (select-window wind-C)
1763 (if past-last-diff (goto-char (point-max)))
1764 (condition-case nil
1765 (backward-char shift) ; noerror, if beginning of buffer
1766 (error))
1767 (recenter)
1768 ))
1769 (select-window ctl-wind)
1770 ))
1771 ))
475f9031
KH
1772
1773
1774;; find region most related to the current point position (or POS, if given)
bbe6126c
MK
1775;; returns diff number as seen by the user (i.e., 1+ the internal
1776;; representation)
1777;; The optional argument WHICH-DIFF can be `after' or `before'. If `after',
1778;; find the diff after the point. If `before', find the diff before the
1779;; point. If the point is inside a diff, return that diff.
1780(defun ediff-diff-at-point (buf-type &optional pos which-diff)
475f9031
KH
1781 (let ((buffer (ediff-get-buffer buf-type))
1782 (ctl-buffer ediff-control-buffer)
1783 (max-dif-num (1- ediff-number-of-differences))
1784 (diff-no -1)
1785 (prev-beg 0)
1786 (prev-end 0)
1787 (beg 0)
1788 (end 0))
1789
e756eb9f 1790 (ediff-with-current-buffer buffer
475f9031
KH
1791 (setq pos (or pos (point)))
1792 (while (and (or (< pos prev-beg) (> pos beg))
1793 (< diff-no max-dif-num))
1794 (setq diff-no (1+ diff-no))
1795 (setq prev-beg beg
1796 prev-end end)
1797 (setq beg (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer)
1798 end (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer))
1799 )
1800
bbe6126c
MK
1801 ;; boost diff-no by 1, if past the last diff region
1802 (if (and (memq which-diff '(after before))
1803 (> pos beg) (= diff-no max-dif-num))
1804 (setq diff-no (1+ diff-no)))
1805
1806 (cond ((eq which-diff 'after) (1+ diff-no))
1807 ((eq which-diff 'before) diff-no)
1808 ((< (abs (count-lines pos (max 1 prev-end)))
1809 (abs (count-lines pos (max 1 beg))))
1810 diff-no) ; choose prev difference
1811 (t
1812 (1+ diff-no))) ; choose next difference
475f9031
KH
1813 )))
1814
1815\f
1816;;; Copying diffs.
1817
1818(defun ediff-diff-to-diff (arg &optional keys)
4ae69eac
MK
1819 "Copy buffer-X'th difference region to buffer Y \(X,Y are A, B, or C\).
1820If numerical prefix argument, copy the difference specified in the arg.
475f9031
KH
1821Otherwise, copy the difference given by `ediff-current-difference'.
1822This command assumes it is bound to a 2-character key sequence, `ab', `ba',
1823`ac', etc., which is used to determine the types of buffers to be used for
1824copying difference regions. The first character in the sequence specifies
1825the source buffer and the second specifies the target.
1826
1827If the second optional argument, a 2-character string, is given, use it to
1828determine the source and the target buffers instead of the command keys."
1829 (interactive "P")
651342bc 1830 (ediff-barf-if-not-control-buffer)
475f9031 1831 (or keys (setq keys (this-command-keys)))
bbe6126c
MK
1832 (if (eq arg '-) (setq arg -1)) ; translate neg arg to -1
1833 (if (numberp arg) (ediff-jump-to-difference arg))
1834
475f9031
KH
1835 (let* ((key1 (aref keys 0))
1836 (key2 (aref keys 1))
1837 (char1 (if (and ediff-xemacs-p (eventp key1)) (event-key key1) key1))
651342bc
MK
1838 (char2 (if (and ediff-xemacs-p (eventp key1)) (event-key key2) key2))
1839 ediff-verbose-p)
475f9031
KH
1840 (ediff-copy-diff ediff-current-difference
1841 (ediff-char-to-buftype char1)
1842 (ediff-char-to-buftype char2))
651342bc
MK
1843 ;; recenter with rehighlighting, but no messages
1844 (ediff-recenter)))
475f9031 1845
4ae69eac
MK
1846(defun ediff-copy-A-to-B (arg)
1847 "Copy ARGth difference region from buffer A to B.
1848ARG is a prefix argument. If nil, copy the current difference region."
1849 (interactive "P")
1850 (ediff-diff-to-diff arg "ab"))
1851
1852(defun ediff-copy-B-to-A (arg)
1853 "Copy ARGth difference region from buffer B to A.
1854ARG is a prefix argument. If nil, copy the current difference region."
1855 (interactive "P")
1856 (ediff-diff-to-diff arg "ba"))
1857
1858(defun ediff-copy-A-to-C (arg)
1859 "Copy ARGth difference region from buffer A to buffer C.
1860ARG is a prefix argument. If nil, copy the current difference region."
1861 (interactive "P")
1862 (ediff-diff-to-diff arg "ac"))
1863
1864(defun ediff-copy-B-to-C (arg)
1865 "Copy ARGth difference region from buffer B to buffer C.
1866ARG is a prefix argument. If nil, copy the current difference region."
1867 (interactive "P")
1868 (ediff-diff-to-diff arg "bc"))
1869
1870(defun ediff-copy-C-to-B (arg)
1871 "Copy ARGth difference region from buffer C to B.
1872ARG is a prefix argument. If nil, copy the current difference region."
1873 (interactive "P")
1874 (ediff-diff-to-diff arg "cb"))
1875
1876(defun ediff-copy-C-to-A (arg)
1877 "Copy ARGth difference region from buffer C to A.
1878ARG is a prefix argument. If nil, copy the current difference region."
1879 (interactive "P")
1880 (ediff-diff-to-diff arg "ca"))
1881
1882
475f9031
KH
1883
1884;; Copy diff N from FROM-BUF-TYPE \(given as A, B or C\) to TO-BUF-TYPE.
1885;; If optional DO-NOT-SAVE is non-nil, do not save the old value of the
1886;; target diff. This is used in merging, when constructing the merged
1887;; version.
1888(defun ediff-copy-diff (n from-buf-type to-buf-type
1889 &optional batch-invocation reg-to-copy)
1890 (let* ((to-buf (ediff-get-buffer to-buf-type))
1891 ;;(from-buf (if (not reg-to-copy) (ediff-get-buffer from-buf-type)))
1892 (ctrl-buf ediff-control-buffer)
1893 (saved-p t)
1894 (three-way ediff-3way-job)
1895 messg
1896 ediff-verbose-p
1897 reg-to-delete reg-to-delete-beg reg-to-delete-end)
1898
475f9031
KH
1899 (setq reg-to-delete-beg
1900 (ediff-get-diff-posn to-buf-type 'beg n ctrl-buf))
1901 (setq reg-to-delete-end
1902 (ediff-get-diff-posn to-buf-type 'end n ctrl-buf))
1903
1904 (if reg-to-copy
1905 (setq from-buf-type nil)
1906 (setq reg-to-copy (ediff-get-region-contents n from-buf-type ctrl-buf)))
1907
1908 (setq reg-to-delete (ediff-get-region-contents
1909 n to-buf-type ctrl-buf
1910 reg-to-delete-beg reg-to-delete-end))
1911
475f9031 1912 (if (string= reg-to-delete reg-to-copy)
4ae69eac 1913 (setq saved-p nil) ; don't copy identical buffers
475f9031
KH
1914 ;; seems ok to copy
1915 (if (or batch-invocation (ediff-test-save-region n to-buf-type))
1916 (condition-case conds
1917 (progn
e756eb9f 1918 (ediff-with-current-buffer to-buf
475f9031 1919 ;; to prevent flags from interfering if buffer is writable
41d25ad0 1920 (let ((inhibit-read-only (null buffer-read-only)))
475f9031
KH
1921
1922 (goto-char reg-to-delete-end)
4ae69eac 1923 (insert reg-to-copy)
475f9031 1924
4ae69eac
MK
1925 (if (> reg-to-delete-end reg-to-delete-beg)
1926 (kill-region reg-to-delete-beg reg-to-delete-end))
475f9031
KH
1927 ))
1928 (or batch-invocation
1929 (setq
1930 messg
1931 (ediff-save-diff-region n to-buf-type reg-to-delete))))
1932 (error (message "ediff-copy-diff: %s %s"
1933 (car conds)
1934 (mapconcat 'prin1-to-string (cdr conds) " "))
1935 (beep 1)
651342bc 1936 (sit-for 2) ; let the user see the error msg
475f9031
KH
1937 (setq saved-p nil)
1938 )))
1939 )
1940
1941 ;; adjust state of difference in case 3-way and diff was copied ok
1942 (if (and saved-p three-way)
41d25ad0 1943 (ediff-set-state-of-diff-in-all-buffers n ctrl-buf))
475f9031
KH
1944
1945 (if batch-invocation
1946 (ediff-clear-fine-differences n)
1947 ;; If diff3 job, we should recompute fine diffs so we clear them
1948 ;; before reinserting flags (and thus before ediff-recenter).
1949 (if (and saved-p three-way)
1950 (ediff-clear-fine-differences n))
41d25ad0
KH
1951
1952 (ediff-refresh-mode-lines)
1953
475f9031
KH
1954 ;; For diff2 jobs, don't recompute fine diffs, since we know there
1955 ;; aren't any. So we clear diffs after ediff-recenter.
1956 (if (and saved-p (not three-way))
1957 (ediff-clear-fine-differences n))
1958 ;; Make sure that the message about saving and how to restore is seen
1959 ;; by the user
1960 (message messg))
1961 ))
1962
1963;; Save Nth diff of buffer BUF-TYPE \(A, B, or C\).
1964;; That is to say, the Nth diff on the `ediff-killed-diffs-alist'. REG
1965;; is the region to save. It is redundant here, but is passed anyway, for
1966;; convenience.
1967(defun ediff-save-diff-region (n buf-type reg)
1968 (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist))
1969 (buf (ediff-get-buffer buf-type))
1970 (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved))))
1971
1972 (if this-buf-n-th-diff-saved
1973 ;; either nothing saved for n-th diff and buffer or we OK'ed
1974 ;; overriding
1975 (setcdr this-buf-n-th-diff-saved reg)
1976 (if n-th-diff-saved ;; n-th diff saved, but for another buffer
1977 (nconc n-th-diff-saved (list (cons buf reg)))
1978 (setq ediff-killed-diffs-alist ;; create record for n-th diff
1979 (cons (list n (cons buf reg))
1980 ediff-killed-diffs-alist))))
1981 (message "Saving old diff region #%d of buffer %S. To recover, type `r%s'"
1982 (1+ n) buf-type
1983 (if ediff-merge-job
1984 "" (downcase (symbol-name buf-type))))
1985 ))
1986
1987;; Test if saving Nth difference region of buffer BUF-TYPE is possible.
1988(defun ediff-test-save-region (n buf-type)
1989 (let* ((n-th-diff-saved (assoc n ediff-killed-diffs-alist))
1990 (buf (ediff-get-buffer buf-type))
1991 (this-buf-n-th-diff-saved (assoc buf (cdr n-th-diff-saved))))
1992
1993 (if this-buf-n-th-diff-saved
1994 (if (yes-or-no-p
1995 (format
1996 "You've previously copied diff region %d to buffer %S. Confirm "
1997 (1+ n) buf-type))
1998 t
1999 (error "Quit"))
2000 t)))
2001
2002(defun ediff-pop-diff (n buf-type)
2003 "Pop last killed Nth diff region from buffer BUF-TYPE."
2004 (let* ((n-th-record (assoc n ediff-killed-diffs-alist))
2005 (buf (ediff-get-buffer buf-type))
2006 (saved-rec (assoc buf (cdr n-th-record)))
2007 (three-way ediff-3way-job)
2008 (ctl-buf ediff-control-buffer)
2009 ediff-verbose-p
2010 saved-diff reg-beg reg-end recovered)
2011
2012 (if (cdr saved-rec)
2013 (setq saved-diff (cdr saved-rec))
2014 (if (> ediff-number-of-differences 0)
2015 (error "Nothing saved for diff %d in buffer %S" (1+ n) buf-type)
4ae69eac 2016 (error ediff-NO-DIFFERENCES)))
475f9031 2017
475f9031
KH
2018 (setq reg-beg (ediff-get-diff-posn buf-type 'beg n ediff-control-buffer))
2019 (setq reg-end (ediff-get-diff-posn buf-type 'end n ediff-control-buffer))
475f9031
KH
2020
2021 (condition-case conds
e756eb9f 2022 (ediff-with-current-buffer buf
41d25ad0 2023 (let ((inhibit-read-only (null buffer-read-only)))
475f9031
KH
2024
2025 (goto-char reg-end)
4ae69eac 2026 (insert saved-diff)
475f9031 2027
4ae69eac
MK
2028 (if (> reg-end reg-beg)
2029 (kill-region reg-beg reg-end))
475f9031
KH
2030
2031 (setq recovered t)
2032 ))
2033 (error (message "ediff-pop-diff: %s %s"
2034 (car conds)
2035 (mapconcat 'prin1-to-string (cdr conds) " "))
2036 (beep 1)))
2037
41d25ad0
KH
2038 ;; Clearing fine diffs is necessary for
2039 ;; ediff-unselect-and-select-difference to properly recompute them. We
2040 ;; can't rely on ediff-copy-diff to clear this vector, as the user might
2041 ;; have modified diff regions after copying and, thus, may have recomputed
2042 ;; fine diffs.
475f9031
KH
2043 (if recovered
2044 (ediff-clear-fine-differences n))
2045
2046 ;; adjust state of difference
2047 (if (and three-way recovered)
2048 (ediff-set-state-of-diff-in-all-buffers n ctl-buf))
2049
41d25ad0
KH
2050 (ediff-refresh-mode-lines)
2051
475f9031
KH
2052 (if recovered
2053 (progn
2054 (setq n-th-record (delq saved-rec n-th-record))
2055 (message "Diff region %d in buffer %S restored" (1+ n) buf-type)
2056 ))
2057 ))
2058
2059(defun ediff-restore-diff (arg &optional key)
2060 "Restore ARGth diff from `ediff-killed-diffs-alist'.
4ae69eac 2061ARG is a prefix argument. If ARG is nil, restore the current-difference.
475f9031
KH
2062If the second optional argument, a character, is given, use it to
2063determine the target buffer instead of last-command-char"
2064 (interactive "P")
651342bc 2065 (ediff-barf-if-not-control-buffer)
4ae69eac 2066 (if (numberp arg)
475f9031
KH
2067 (ediff-jump-to-difference arg))
2068 (ediff-pop-diff ediff-current-difference
2069 (ediff-char-to-buftype (or key last-command-char)))
651342bc
MK
2070 ;; recenter with rehighlighting, but no messages
2071 (let (ediff-verbose-p)
2072 (ediff-recenter)))
4ae69eac
MK
2073
2074(defun ediff-restore-diff-in-merge-buffer (arg)
2075 "Restore ARGth diff in the merge buffer.
2076ARG is a prefix argument. If nil, restore the current diff."
2077 (interactive "P")
2078 (ediff-restore-diff arg ?c))
2079
475f9031
KH
2080
2081(defun ediff-toggle-regexp-match ()
2082 "Toggle between focusing and hiding of difference regions that match
2083a regular expression typed in by the user."
2084 (interactive)
651342bc 2085 (ediff-barf-if-not-control-buffer)
475f9031
KH
2086 (let ((regexp-A "")
2087 (regexp-B "")
2088 (regexp-C "")
2089 msg-connective alt-msg-connective alt-connective)
2090 (cond
2091 ((or (and (eq ediff-skip-diff-region-function
bbe6126c 2092 ediff-focus-on-regexp-matches-function)
475f9031 2093 (eq last-command-char ?f))
651342bc
MK
2094 (and (eq ediff-skip-diff-region-function
2095 ediff-hide-regexp-matches-function)
475f9031
KH
2096 (eq last-command-char ?h)))
2097 (message "Selective browsing by regexp turned off")
2098 (setq ediff-skip-diff-region-function 'ediff-show-all-diffs))
2099 ((eq last-command-char ?h)
651342bc 2100 (setq ediff-skip-diff-region-function ediff-hide-regexp-matches-function
475f9031
KH
2101 regexp-A
2102 (read-string
2103 (format
2104 "Ignore A-regions matching this regexp (default \"%s\"): "
2105 ediff-regexp-hide-A))
2106 regexp-B
2107 (read-string
2108 (format
2109 "Ignore B-regions matching this regexp (default \"%s\"): "
2110 ediff-regexp-hide-B)))
2111 (if ediff-3way-comparison-job
2112 (setq regexp-C
2113 (read-string
2114 (format
2115 "Ignore C-regions matching this regexp (default \"%s\"): "
2116 ediff-regexp-hide-C))))
2117 (if (eq ediff-hide-regexp-connective 'and)
2118 (setq msg-connective "BOTH"
2119 alt-msg-connective "ONE OF"
2120 alt-connective 'or)
2121 (setq msg-connective "ONE OF"
2122 alt-msg-connective "BOTH"
2123 alt-connective 'and))
2124 (if (y-or-n-p
2125 (format
651342bc 2126 "Ignore regions that match %s regexps, OK? "
475f9031 2127 msg-connective alt-msg-connective))
651342bc
MK
2128 (message "Will ignore regions that match %s regexps" msg-connective)
2129 (setq ediff-hide-regexp-connective alt-connective)
2130 (message "Will ignore regions that match %s regexps"
2131 alt-msg-connective))
2132
475f9031
KH
2133 (or (string= regexp-A "") (setq ediff-regexp-hide-A regexp-A))
2134 (or (string= regexp-B "") (setq ediff-regexp-hide-B regexp-B))
2135 (or (string= regexp-C "") (setq ediff-regexp-hide-C regexp-C)))
651342bc 2136
475f9031 2137 ((eq last-command-char ?f)
651342bc
MK
2138 (setq ediff-skip-diff-region-function
2139 ediff-focus-on-regexp-matches-function
475f9031
KH
2140 regexp-A
2141 (read-string
2142 (format
2143 "Focus on A-regions matching this regexp (default \"%s\"): "
2144 ediff-regexp-focus-A))
2145 regexp-B
2146 (read-string
2147 (format
2148 "Focus on B-regions matching this regexp (default \"%s\"): "
2149 ediff-regexp-focus-B)))
2150 (if ediff-3way-comparison-job
2151 (setq regexp-C
2152 (read-string
2153 (format
2154 "Focus on C-regions matching this regexp (default \"%s\"): "
2155 ediff-regexp-focus-C))))
2156 (if (eq ediff-focus-regexp-connective 'and)
2157 (setq msg-connective "BOTH"
2158 alt-msg-connective "ONE OF"
2159 alt-connective 'or)
2160 (setq msg-connective "ONE OF"
2161 alt-msg-connective "BOTH"
2162 alt-connective 'and))
2163 (if (y-or-n-p
2164 (format
651342bc 2165 "Focus on regions that match %s regexps, OK? "
475f9031 2166 msg-connective alt-msg-connective))
651342bc
MK
2167 (message "Will focus on regions that match %s regexps"
2168 msg-connective)
2169 (setq ediff-focus-regexp-connective alt-connective)
2170 (message "Will focus on regions that match %s regexps"
2171 alt-msg-connective))
2172
475f9031
KH
2173 (or (string= regexp-A "") (setq ediff-regexp-focus-A regexp-A))
2174 (or (string= regexp-B "") (setq ediff-regexp-focus-B regexp-B))
2175 (or (string= regexp-C "") (setq ediff-regexp-focus-C regexp-C))))))
2176
2177(defun ediff-toggle-skip-similar ()
2178 (interactive)
651342bc 2179 (ediff-barf-if-not-control-buffer)
475f9031
KH
2180 (if (not (eq ediff-auto-refine 'on))
2181 (error
2182 "Can't skip over whitespace regions: first turn auto-refining on"))
2183 (setq ediff-ignore-similar-regions (not ediff-ignore-similar-regions))
2184 (if ediff-ignore-similar-regions
2185 (message
2186 "Skipping regions that differ only in white space & line breaks")
2187 (message "Skipping over white-space differences turned off")))
2188
2189(defun ediff-focus-on-regexp-matches (n)
2190 "Focus on diffs that match regexp `ediff-regexp-focus-A/B'.
2191Regions to be ignored according to this function are those where
2192buf A region doesn't match `ediff-regexp-focus-A' and buf B region
2193doesn't match `ediff-regexp-focus-B'.
2194This function returns nil if the region number N (specified as
2195an argument) is not to be ignored and t if region N is to be ignored.
2196
2197N is a region number used by Ediff internally. It is 1 less
2198the number seen by the user."
2199 (if (ediff-valid-difference-p n)
2200 (let* ((ctl-buf ediff-control-buffer)
2201 (regex-A ediff-regexp-focus-A)
2202 (regex-B ediff-regexp-focus-B)
2203 (regex-C ediff-regexp-focus-C)
e756eb9f 2204 (reg-A-match (ediff-with-current-buffer ediff-buffer-A
4ae69eac
MK
2205 (save-restriction
2206 (narrow-to-region
2207 (ediff-get-diff-posn 'A 'beg n ctl-buf)
2208 (ediff-get-diff-posn 'A 'end n ctl-buf))
2209 (goto-char (point-min))
2210 (re-search-forward regex-A nil t))))
e756eb9f 2211 (reg-B-match (ediff-with-current-buffer ediff-buffer-B
4ae69eac
MK
2212 (save-restriction
2213 (narrow-to-region
2214 (ediff-get-diff-posn 'B 'beg n ctl-buf)
2215 (ediff-get-diff-posn 'B 'end n ctl-buf))
2216 (re-search-forward regex-B nil t))))
475f9031 2217 (reg-C-match (if ediff-3way-comparison-job
e756eb9f 2218 (ediff-with-current-buffer ediff-buffer-C
4ae69eac
MK
2219 (save-restriction
2220 (narrow-to-region
2221 (ediff-get-diff-posn 'C 'beg n ctl-buf)
2222 (ediff-get-diff-posn 'C 'end n ctl-buf))
2223 (re-search-forward regex-C nil t))))))
475f9031
KH
2224 (not (eval (if ediff-3way-comparison-job
2225 (list ediff-focus-regexp-connective
2226 reg-A-match reg-B-match reg-C-match)
2227 (list ediff-focus-regexp-connective
2228 reg-A-match reg-B-match))))
2229 )))
2230
2231(defun ediff-hide-regexp-matches (n)
2232 "Hide diffs that match regexp `ediff-regexp-hide-A/B/C'.
2233Regions to be ignored are those where buf A region matches
2234`ediff-regexp-hide-A' and buf B region matches `ediff-regexp-hide-B'.
2235This function returns nil if the region number N (specified as
2236an argument) is not to be ignored and t if region N is to be ignored.
2237
2238N is a region number used by Ediff internally. It is 1 less
2239the number seen by the user."
2240 (if (ediff-valid-difference-p n)
2241 (let* ((ctl-buf ediff-control-buffer)
2242 (regex-A ediff-regexp-hide-A)
2243 (regex-B ediff-regexp-hide-B)
2244 (regex-C ediff-regexp-hide-C)
e756eb9f 2245 (reg-A-match (ediff-with-current-buffer ediff-buffer-A
4ae69eac
MK
2246 (save-restriction
2247 (narrow-to-region
2248 (ediff-get-diff-posn 'A 'beg n ctl-buf)
2249 (ediff-get-diff-posn 'A 'end n ctl-buf))
2250 (goto-char (point-min))
2251 (re-search-forward regex-A nil t))))
e756eb9f 2252 (reg-B-match (ediff-with-current-buffer ediff-buffer-B
4ae69eac
MK
2253 (save-restriction
2254 (narrow-to-region
2255 (ediff-get-diff-posn 'B 'beg n ctl-buf)
2256 (ediff-get-diff-posn 'B 'end n ctl-buf))
2257 (goto-char (point-min))
2258 (re-search-forward regex-B nil t))))
475f9031 2259 (reg-C-match (if ediff-3way-comparison-job
e756eb9f 2260 (ediff-with-current-buffer ediff-buffer-C
4ae69eac
MK
2261 (save-restriction
2262 (narrow-to-region
2263 (ediff-get-diff-posn 'C 'beg n ctl-buf)
2264 (ediff-get-diff-posn 'C 'end n ctl-buf))
2265 (goto-char (point-min))
2266 (re-search-forward regex-C nil t))))))
475f9031
KH
2267 (eval (if ediff-3way-comparison-job
2268 (list ediff-hide-regexp-connective
2269 reg-A-match reg-B-match reg-C-match)
2270 (list ediff-hide-regexp-connective reg-A-match reg-B-match)))
2271 )))
2272
2273
2274\f
2275;;; Quitting, suspending, etc.
2276
651342bc 2277(defun ediff-quit (reverse-default-keep-variants)
475f9031
KH
2278 "Finish an Ediff session and exit Ediff.
2279Unselects the selected difference, if any, restores the read-only and modified
2280flags of the compared file buffers, kills Ediff buffers for this session
651342bc
MK
2281\(but not buffers A, B, C\).
2282
2283If `ediff-keep-variants' is nil, the user will be asked whether the buffers
2284containing the variants should be removed \(if they haven't been modified\).
2285If it is t, they will be preserved unconditionally. A prefix argument,
2286temporarily reverses the meaning of this variable."
2287 (interactive "P")
2288 (ediff-barf-if-not-control-buffer)
ddc90f39
MK
2289 (let ((ctl-buf (current-buffer)))
2290 (if (y-or-n-p (format "Quit this Ediff session%s? "
2291 (if (ediff-buffer-live-p ediff-meta-buffer)
2292 " & show containing session group" "")))
2293 (progn
2294 (message "")
2295 (set-buffer ctl-buf)
2296 (ediff-really-quit reverse-default-keep-variants))
2297 (message ""))))
475f9031
KH
2298
2299
2300;; Perform the quit operations.
651342bc 2301(defun ediff-really-quit (reverse-default-keep-variants)
475f9031
KH
2302 (ediff-unhighlight-diffs-totally)
2303 (ediff-clear-diff-vector 'ediff-difference-vector-A 'fine-diffs-also)
2304 (ediff-clear-diff-vector 'ediff-difference-vector-B 'fine-diffs-also)
2305 (ediff-clear-diff-vector 'ediff-difference-vector-C 'fine-diffs-also)
651342bc
MK
2306 (ediff-clear-diff-vector 'ediff-difference-vector-Ancestor 'fine-diffs-also)
2307
475f9031
KH
2308 (ediff-delete-temp-files)
2309
2310 ;; Restore visibility range. This affects only ediff-*-regions/windows.
2311 ;; Since for other job names ediff-visible-region sets
2312 ;; ediff-visible-bounds to ediff-wide-bounds, the settings below are
2313 ;; ignored for such jobs.
2314 (if ediff-quit-widened
2315 (setq ediff-visible-bounds ediff-wide-bounds)
2316 (setq ediff-visible-bounds ediff-narrow-bounds))
2317
2318 ;; Apply selective display to narrow or widen
2319 (ediff-visible-region)
2320 (mapcar (function (lambda (overl)
2321 (if (ediff-overlayp overl)
2322 (ediff-delete-overlay overl))))
2323 ediff-wide-bounds)
2324 (mapcar (function (lambda (overl)
2325 (if (ediff-overlayp overl)
2326 (ediff-delete-overlay overl))))
2327 ediff-narrow-bounds)
92c51e07 2328
475f9031 2329 ;; restore buffer mode line id's in buffer-A/B/C
651342bc 2330 (let ((control-buffer ediff-control-buffer)
92c51e07 2331 (meta-buffer ediff-meta-buffer)
328b4b70 2332 (session-number ediff-meta-session-number)
92c51e07
MK
2333 ;; suitable working frame
2334 (warp-frame (if (and (ediff-window-display-p) (eq ediff-grab-mouse t))
2335 (cond ((window-live-p ediff-window-A)
2336 (window-frame ediff-window-A))
2337 ((window-live-p ediff-window-B)
2338 (window-frame ediff-window-B))
2339 (t (next-frame))))))
475f9031 2340 (condition-case nil
e756eb9f 2341 (ediff-with-current-buffer ediff-buffer-A
651342bc
MK
2342 (setq ediff-this-buffer-ediff-sessions
2343 (delq control-buffer ediff-this-buffer-ediff-sessions))
475f9031
KH
2344 (kill-local-variable 'mode-line-buffer-identification)
2345 (kill-local-variable 'mode-line-format)
2346 )
2347 (error))
2348
2349 (condition-case nil
e756eb9f 2350 (ediff-with-current-buffer ediff-buffer-B
651342bc
MK
2351 (setq ediff-this-buffer-ediff-sessions
2352 (delq control-buffer ediff-this-buffer-ediff-sessions))
475f9031
KH
2353 (kill-local-variable 'mode-line-buffer-identification)
2354 (kill-local-variable 'mode-line-format)
2355 )
2356 (error))
2357
2358 (condition-case nil
e756eb9f 2359 (ediff-with-current-buffer ediff-buffer-C
651342bc
MK
2360 (setq ediff-this-buffer-ediff-sessions
2361 (delq control-buffer ediff-this-buffer-ediff-sessions))
2362 (kill-local-variable 'mode-line-buffer-identification)
2363 (kill-local-variable 'mode-line-format)
2364 )
2365 (error))
2366
2367 (condition-case nil
e756eb9f 2368 (ediff-with-current-buffer ediff-ancestor-buffer
651342bc
MK
2369 (setq ediff-this-buffer-ediff-sessions
2370 (delq control-buffer ediff-this-buffer-ediff-sessions))
475f9031
KH
2371 (kill-local-variable 'mode-line-buffer-identification)
2372 (kill-local-variable 'mode-line-format)
2373 )
2374 (error))
651342bc
MK
2375
2376 (setq ediff-session-registry
2377 (delq ediff-control-buffer ediff-session-registry))
2378 (ediff-update-registry)
475f9031
KH
2379 ;; restore state of buffers to what it was before ediff
2380 (ediff-restore-protected-variables)
92c51e07
MK
2381
2382 ;; If the user interrupts (canceling saving the merge buffer), continue
2383 ;; normally.
2384 (condition-case nil
2385 (if (ediff-merge-job)
2386 (run-hooks 'ediff-quit-merge-hook))
2387 (quit))
2388
41d25ad0 2389 ;; good place to kill buffers A/B/C
651342bc
MK
2390 (run-hooks 'ediff-cleanup-hook)
2391 (let ((ediff-keep-variants ediff-keep-variants))
2392 (if reverse-default-keep-variants
2393 (setq ediff-keep-variants (not ediff-keep-variants)))
2394 (or ediff-keep-variants (ediff-janitor 'ask)))
2395
2396 (run-hooks 'ediff-quit-hook)
328b4b70 2397 (ediff-update-meta-buffer meta-buffer nil session-number)
92c51e07
MK
2398
2399 ;; warp mouse into a working window
2400 (setq warp-frame ; if mouse is over a reasonable frame, use it
28650cf1 2401 (cond ((ediff-good-frame-under-mouse))
92c51e07
MK
2402 (t warp-frame)))
2403 (if (frame-live-p warp-frame)
2404 (set-mouse-position (if ediff-emacs-p
2405 warp-frame
2406 (frame-selected-window warp-frame))
2407 2 1))
2408
651342bc 2409 (if (ediff-buffer-live-p meta-buffer)
328b4b70 2410 (ediff-show-meta-buffer meta-buffer session-number))
651342bc 2411 ))
28650cf1
MK
2412
2413;; Returns frame under mouse, if this frame is not a minibuffer
2414;; frame. Otherwise: nil
2415(defun ediff-good-frame-under-mouse ()
2416 (let ((frame-or-win (car (mouse-position)))
2417 (buf-name "")
2418 frame obj-ok)
2419 (setq obj-ok
2420 (if ediff-emacs-p
2421 (frame-live-p frame-or-win)
2422 (window-live-p frame-or-win)))
2423 (if obj-ok
2424 (setq frame (if ediff-emacs-p frame-or-win (window-frame frame-or-win))
2425 buf-name
2426 (buffer-name (window-buffer (frame-selected-window frame)))))
2427 (if (string-match "Minibuf" buf-name)
2428 nil
2429 frame)))
475f9031
KH
2430
2431
2432(defun ediff-delete-temp-files ()
328b4b70 2433 (if (and (stringp ediff-temp-file-A) (file-exists-p ediff-temp-file-A))
475f9031 2434 (delete-file ediff-temp-file-A))
328b4b70 2435 (if (and (stringp ediff-temp-file-B) (file-exists-p ediff-temp-file-B))
475f9031 2436 (delete-file ediff-temp-file-B))
328b4b70 2437 (if (and (stringp ediff-temp-file-C) (file-exists-p ediff-temp-file-C))
475f9031
KH
2438 (delete-file ediff-temp-file-C)))
2439
2440
2441;; Kill control buffer, other auxiliary Ediff buffers.
2442;; Leave one of the frames split between buffers A/B/C
2443(defun ediff-cleanup-mess ()
2444 (let ((buff-A ediff-buffer-A)
2445 (buff-B ediff-buffer-B)
2446 (buff-C ediff-buffer-C)
2447 (ctl-buf ediff-control-buffer)
2448 (ctl-frame ediff-control-frame)
2449 (three-way-job ediff-3way-job))
2450
2451 (ediff-kill-buffer-carefully ediff-diff-buffer)
2452 (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
2453 (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
2454 (ediff-kill-buffer-carefully ediff-tmp-buffer)
2455 (ediff-kill-buffer-carefully ediff-error-buffer)
475f9031
KH
2456 (ediff-kill-buffer-carefully ediff-msg-buffer)
2457 (ediff-kill-buffer-carefully ediff-debug-buffer)
ddc90f39
MK
2458 (if (boundp 'ediff-patch-diagnostics)
2459 (ediff-kill-buffer-carefully ediff-patch-diagnostics))
475f9031 2460
41d25ad0
KH
2461 (if (and (ediff-window-display-p) (frame-live-p ctl-frame))
2462 (delete-frame ctl-frame))
bf5d92c5
MK
2463 ;; Hide bottom toolbar. --marcpa
2464 (if (not (ediff-multiframe-setup-p))
2465 (ediff-kill-bottom-toolbar))
2466
475f9031
KH
2467 (ediff-kill-buffer-carefully ctl-buf)
2468
2469 (delete-other-windows)
2470
2471 ;; display only if not visible
2472 (condition-case nil
2473 (or (ediff-get-visible-buffer-window buff-B)
2474 (switch-to-buffer buff-B))
2475 (error))
2476 (condition-case nil
2477 (or (ediff-get-visible-buffer-window buff-A)
2478 (progn
2479 (if (ediff-get-visible-buffer-window buff-B)
92c51e07 2480 (funcall ediff-split-window-function))
475f9031
KH
2481 (switch-to-buffer buff-A)))
2482 (error))
2483 (if three-way-job
2484 (condition-case nil
2485 (or (ediff-get-visible-buffer-window buff-C)
2486 (progn
2487 (if (or (ediff-get-visible-buffer-window buff-A)
2488 (ediff-get-visible-buffer-window buff-B))
92c51e07 2489 (funcall ediff-split-window-function))
475f9031
KH
2490 (switch-to-buffer buff-C)
2491 (balance-windows)))
2492 (error)))
2493 (message "")
2494 ))
41d25ad0 2495
651342bc 2496(defun ediff-janitor (&optional ask)
41d25ad0
KH
2497 "Kill buffers A, B, and, possibly, C, if these buffers aren't modified.
2498In merge jobs, buffer C is never deleted.
2499However, the side effect of cleaning up may be that you cannot compare the same
2500buffer in two separate Ediff sessions: quitting one of them will delete this
2501buffer in another session as well."
2502 (or (not (ediff-buffer-live-p ediff-buffer-A))
2503 (buffer-modified-p ediff-buffer-A)
651342bc
MK
2504 (and ask
2505 (not (y-or-n-p (format "Kill buffer A [%s]? "
2506 (buffer-name ediff-buffer-A)))))
41d25ad0
KH
2507 (ediff-kill-buffer-carefully ediff-buffer-A))
2508 (or (not (ediff-buffer-live-p ediff-buffer-B))
2509 (buffer-modified-p ediff-buffer-B)
651342bc
MK
2510 (and ask
2511 (not (y-or-n-p (format "Kill buffer B [%s]? "
2512 (buffer-name ediff-buffer-B)))))
41d25ad0
KH
2513 (ediff-kill-buffer-carefully ediff-buffer-B))
2514 (if ediff-merge-job ; don't del buf C if merging--del ancestor buf instead
2515 (or (not (ediff-buffer-live-p ediff-ancestor-buffer))
2516 (buffer-modified-p ediff-ancestor-buffer)
651342bc
MK
2517 (and ask
2518 (not (y-or-n-p (format "Kill the ancestor buffer [%s]? "
2519 (buffer-name ediff-ancestor-buffer)))))
41d25ad0
KH
2520 (ediff-kill-buffer-carefully ediff-ancestor-buffer))
2521 (or (not (ediff-buffer-live-p ediff-buffer-C))
2522 (buffer-modified-p ediff-buffer-C)
651342bc
MK
2523 (and ask (not (y-or-n-p (format "Kill buffer C [%s]? "
2524 (buffer-name ediff-buffer-C)))))
41d25ad0
KH
2525 (ediff-kill-buffer-carefully ediff-buffer-C))))
2526
ddc90f39 2527(defun ediff-maybe-save-and-delete-merge (&optional save-and-continue)
92c51e07 2528 "Default hook to run on quitting a merge job.
ddc90f39
MK
2529This can also be used to save merge buffer in the middle of an Ediff session.
2530
2531If the optional SAVE-AND-CONTINUE argument is non-nil, save merge buffer and
2532continue. Otherwise:
92c51e07
MK
2533If `ediff-autostore-merges' is nil, this does nothing.
2534If it is t, it saves the merge buffer in the file `ediff-merge-store-file'
ddc90f39 2535or asks the user, if the latter is nil. It then asks the user whether to
92c51e07
MK
2536delete the merge buffer.
2537If `ediff-autostore-merges' is neither nil nor t, the merge buffer is saved
2538only if this merge job is part of a group, i.e., was invoked from within
2539`ediff-merge-directories', `ediff-merge-directory-revisions', and such."
ddc90f39
MK
2540 (let ((merge-store-file ediff-merge-store-file)
2541 (ediff-autostore-merges ; fake ediff-autostore-merges, if necessary
2542 (if save-and-continue t ediff-autostore-merges)))
92c51e07
MK
2543 (if ediff-autostore-merges
2544 (cond ((stringp ediff-merge-store-file)
2545 ;; store, ask to delete
ddc90f39
MK
2546 (ediff-write-merge-buffer-and-maybe-kill
2547 ediff-buffer-C merge-store-file 'show-file save-and-continue))
92c51e07
MK
2548 ((eq ediff-autostore-merges t)
2549 ;; ask for file name
2550 (setq merge-store-file
ddc90f39
MK
2551 (read-file-name "Save the merge buffer in file: "))
2552 (ediff-write-merge-buffer-and-maybe-kill
2553 ediff-buffer-C merge-store-file nil save-and-continue))
bf5d92c5 2554 ((and (ediff-buffer-live-p ediff-meta-buffer)
e756eb9f 2555 (ediff-with-current-buffer ediff-meta-buffer
bf5d92c5 2556 (ediff-merge-metajob)))
92c51e07
MK
2557 ;; This case shouldn't occur, as the parent metajob must pass on
2558 ;; a file name, ediff-merge-store-file, where to save the result
2559 ;; of the merge.
2560 ;; Ask where to save anyway--will decide what to do here later.
2561 (setq merge-store-file
ddc90f39
MK
2562 (read-file-name "Save the merge buffer in file: "))
2563 (ediff-write-merge-buffer-and-maybe-kill
2564 ediff-buffer-C merge-store-file nil save-and-continue))))
92c51e07
MK
2565 ))
2566
ddc90f39
MK
2567;; write merge buffer. If the optional argument save-and-continue is non-nil,
2568;; then don't kill the merge buffer
2569(defun ediff-write-merge-buffer-and-maybe-kill (buf file
2570 &optional
2571 show-file save-and-continue)
e756eb9f 2572 (ediff-with-current-buffer buf
92c51e07
MK
2573 (if (or (not (file-exists-p file))
2574 (y-or-n-p (format "File %s exists, overwrite? " file)))
2575 (progn
2576 (write-region (point-min) (point-max) file)
2577 (if show-file
2578 (progn
2579 (message "Merge buffer saved in: %s" file)
328b4b70 2580 (set-buffer-modified-p nil)
92c51e07 2581 (sit-for 2)))
ddc90f39
MK
2582 (if (and
2583 (not save-and-continue)
2584 (y-or-n-p "Merge buffer saved in file. Now kill the buffer? "))
92c51e07
MK
2585 (ediff-kill-buffer-carefully buf))))))
2586
475f9031
KH
2587;; The default way of suspending Ediff.
2588;; Buries Ediff buffers, kills all windows.
651342bc 2589(defun ediff-default-suspend-function ()
475f9031
KH
2590 (let* ((buf-A ediff-buffer-A)
2591 (buf-B ediff-buffer-B)
2592 (buf-C ediff-buffer-C)
2593 (buf-A-wind (ediff-get-visible-buffer-window buf-A))
2594 (buf-B-wind (ediff-get-visible-buffer-window buf-B))
2595 (buf-C-wind (ediff-get-visible-buffer-window buf-C))
ddc90f39
MK
2596 (buf-patch (if (boundp 'ediff-patchbufer) ediff-patchbufer nil))
2597 (buf-patch-diag (if (boundp 'ediff-patch-diagnostics)
2598 ediff-patch-diagnostics nil))
475f9031
KH
2599 (buf-err ediff-error-buffer)
2600 (buf-diff ediff-diff-buffer)
2601 (buf-custom-diff ediff-custom-diff-buffer)
2602 (buf-fine-diff ediff-fine-diff-buffer))
2603
2604 ;; hide the control panel
41d25ad0
KH
2605 (if (and (ediff-window-display-p) (frame-live-p ediff-control-frame))
2606 (iconify-frame ediff-control-frame)
475f9031
KH
2607 (bury-buffer))
2608 (if buf-err (bury-buffer buf-err))
2609 (if buf-diff (bury-buffer buf-diff))
2610 (if buf-custom-diff (bury-buffer buf-custom-diff))
2611 (if buf-fine-diff (bury-buffer buf-fine-diff))
2612 (if buf-patch (bury-buffer buf-patch))
2613 (if buf-patch-diag (bury-buffer buf-patch-diag))
2614 (if (window-live-p buf-A-wind)
2615 (progn
2616 (select-window buf-A-wind)
2617 (delete-other-windows)
2618 (bury-buffer))
ddc90f39
MK
2619 (if (ediff-buffer-live-p buf-A)
2620 (progn
2621 (set-buffer buf-A)
2622 (bury-buffer))))
475f9031
KH
2623 (if (window-live-p buf-B-wind)
2624 (progn
2625 (select-window buf-B-wind)
2626 (delete-other-windows)
2627 (bury-buffer))
ddc90f39
MK
2628 (if (ediff-buffer-live-p buf-B)
2629 (progn
2630 (set-buffer buf-B)
2631 (bury-buffer))))
475f9031
KH
2632 (if (window-live-p buf-C-wind)
2633 (progn
2634 (select-window buf-C-wind)
2635 (delete-other-windows)
2636 (bury-buffer))
ddc90f39
MK
2637 (if (ediff-buffer-live-p buf-C)
2638 (progn
2639 (set-buffer buf-C)
2640 (bury-buffer))))
475f9031
KH
2641 ))
2642
2643
2644(defun ediff-suspend ()
2645 "Suspend Ediff.
2646To resume, switch to the appropriate `Ediff Control Panel'
2647buffer and then type \\[ediff-recenter]. Ediff will automatically set
2648up an appropriate window config."
2649 (interactive)
651342bc
MK
2650 (ediff-barf-if-not-control-buffer)
2651 (run-hooks 'ediff-suspend-hook)
475f9031 2652 (message
651342bc 2653 "To resume, type M-x eregistry and select the desired Ediff session"))
475f9031
KH
2654
2655
2656(defun ediff-status-info ()
2657 "Show the names of the buffers or files being operated on by Ediff.
2658Hit \\[ediff-recenter] to reset the windows afterward."
2659 (interactive)
651342bc
MK
2660 (ediff-barf-if-not-control-buffer)
2661 (save-excursion
2662 (ediff-skip-unsuitable-frames))
bbe6126c
MK
2663 (with-output-to-temp-buffer ediff-msg-buffer
2664 (raise-frame (selected-frame))
475f9031
KH
2665 (princ (ediff-version))
2666 (princ "\n\n")
e756eb9f 2667 (ediff-with-current-buffer ediff-buffer-A
475f9031
KH
2668 (if buffer-file-name
2669 (princ
2670 (format "File A = %S\n" buffer-file-name))
2671 (princ
2672 (format "Buffer A = %S\n" (buffer-name)))))
e756eb9f 2673 (ediff-with-current-buffer ediff-buffer-B
475f9031
KH
2674 (if buffer-file-name
2675 (princ
2676 (format "File B = %S\n" buffer-file-name))
2677 (princ
2678 (format "Buffer B = %S\n" (buffer-name)))))
2679 (if ediff-3way-job
e756eb9f 2680 (ediff-with-current-buffer ediff-buffer-C
475f9031
KH
2681 (if buffer-file-name
2682 (princ
2683 (format "File C = %S\n" buffer-file-name))
2684 (princ
2685 (format "Buffer C = %S\n" (buffer-name))))))
651342bc
MK
2686 (princ (format "Customized diff output %s\n"
2687 (if (ediff-buffer-live-p ediff-custom-diff-buffer)
2688 (concat "\tin buffer "
2689 (buffer-name ediff-custom-diff-buffer))
ddc90f39 2690 " is not available")))
651342bc
MK
2691 (princ (format "Plain diff output %s\n"
2692 (if (ediff-buffer-live-p ediff-diff-buffer)
2693 (concat "\tin buffer "
2694 (buffer-name ediff-diff-buffer))
ddc90f39 2695 " is not available")))
475f9031 2696
e756eb9f 2697 (let* ((A-line (ediff-with-current-buffer ediff-buffer-A
475f9031 2698 (1+ (count-lines (point-min) (point)))))
e756eb9f 2699 (B-line (ediff-with-current-buffer ediff-buffer-B
475f9031
KH
2700 (1+ (count-lines (point-min) (point)))))
2701 C-line)
2702 (princ (format "\Buffer A's point is on line %d\n" A-line))
2703 (princ (format "Buffer B's point is on line %d\n" B-line))
2704 (if ediff-3way-job
2705 (progn
e756eb9f 2706 (setq C-line (ediff-with-current-buffer ediff-buffer-C
475f9031
KH
2707 (1+ (count-lines (point-min) (point)))))
2708 (princ (format "Buffer C's point is on line %d\n" C-line)))))
2709
2710 (princ (format "\nCurrent difference number = %S\n"
2711 (cond ((< ediff-current-difference 0) 'start)
2712 ((>= ediff-current-difference
2713 ediff-number-of-differences) 'end)
2714 (t (1+ ediff-current-difference)))))
2715
4ae69eac 2716 (princ
ddc90f39 2717 (format "\n%s regions that differ in white space & line breaks only"
4ae69eac 2718 (if ediff-ignore-similar-regions
ddc90f39 2719 "Ignoring" "Showing")))
4ae69eac
MK
2720 (if (and ediff-merge-job ediff-show-clashes-only)
2721 (princ
2722 "\nFocusing on regions where both buffers differ from the ancestor"))
475f9031
KH
2723
2724 (cond ((eq ediff-skip-diff-region-function 'ediff-show-all-diffs)
4ae69eac 2725 (princ "\nSelective browsing by regexp is off\n"))
651342bc
MK
2726 ((eq ediff-skip-diff-region-function
2727 ediff-hide-regexp-matches-function)
475f9031
KH
2728 (princ
2729 "\nIgnoring regions that match")
2730 (princ
2731 (format
2732 "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n"
2733 ediff-regexp-hide-A ediff-hide-regexp-connective
2734 ediff-regexp-hide-B)))
651342bc
MK
2735 ((eq ediff-skip-diff-region-function
2736 ediff-focus-on-regexp-matches-function)
475f9031
KH
2737 (princ
2738 "\nFocusing on regions that match")
2739 (princ
2740 (format
2741 "\n\t regexp `%s' in buffer A %S\n\t regexp `%s' in buffer B\n"
2742 ediff-regexp-focus-A ediff-focus-regexp-connective
2743 ediff-regexp-focus-B)))
2744 (t (princ "\nSelective browsing via a user-defined method.\n")))
2745
2746 (princ
2747 (format "\nBugs/suggestions: type `%s' while in Ediff Control Panel."
2748 (substitute-command-keys "\\[ediff-submit-report]")))
651342bc
MK
2749 ) ; with output
2750 (if (frame-live-p ediff-control-frame)
2751 (ediff-reset-mouse ediff-control-frame))
2752 (if (window-live-p ediff-control-window)
2753 (select-window ediff-control-window)))
41d25ad0 2754
475f9031
KH
2755
2756
2757\f
2758;;; Support routines
2759
2760;; Select a difference by placing the ASCII flags around the appropriate
2761;; group of lines in the A, B buffers
2762;; This may have to be modified for buffer C, when it will be supported.
2763(defun ediff-select-difference (n)
2764 (if (and (ediff-buffer-live-p ediff-buffer-A)
2765 (ediff-buffer-live-p ediff-buffer-B)
2766 (ediff-valid-difference-p n))
2767 (progn
4ae69eac 2768 (if (and (ediff-has-face-support-p) ediff-use-faces)
475f9031
KH
2769 (progn
2770 (ediff-highlight-diff n)
2771 (setq ediff-highlighting-style 'face))
2772 (setq ediff-highlighting-style 'ascii)
41d25ad0
KH
2773 (ediff-place-flags-in-buffer
2774 'A ediff-buffer-A ediff-control-buffer n)
2775 (ediff-place-flags-in-buffer
2776 'B ediff-buffer-B ediff-control-buffer n)
475f9031 2777 (if ediff-3way-job
41d25ad0
KH
2778 (ediff-place-flags-in-buffer
2779 'C ediff-buffer-C ediff-control-buffer n))
651342bc
MK
2780 (if (ediff-buffer-live-p ediff-ancestor-buffer)
2781 (ediff-place-flags-in-buffer
2782 'Ancestor ediff-ancestor-buffer
2783 ediff-control-buffer n))
475f9031
KH
2784 )
2785
2786 (ediff-install-fine-diff-if-necessary n)
651342bc 2787 (run-hooks 'ediff-select-hook))))
475f9031
KH
2788
2789
2790;; Unselect a difference by removing the ASCII flags in the buffers.
2791;; This may have to be modified for buffer C, when it will be supported.
2792(defun ediff-unselect-difference (n)
2793 (if (ediff-valid-difference-p n)
2794 (progn
4ae69eac 2795 (cond ((and (ediff-has-face-support-p) ediff-use-faces)
475f9031
KH
2796 (ediff-unhighlight-diff))
2797 ((eq ediff-highlighting-style 'ascii)
2798 (ediff-remove-flags-from-buffer
2799 ediff-buffer-A
41d25ad0 2800 (ediff-get-diff-overlay n 'A))
475f9031
KH
2801 (ediff-remove-flags-from-buffer
2802 ediff-buffer-B
41d25ad0 2803 (ediff-get-diff-overlay n 'B))
475f9031
KH
2804 (if ediff-3way-job
2805 (ediff-remove-flags-from-buffer
2806 ediff-buffer-C
41d25ad0 2807 (ediff-get-diff-overlay n 'C)))
651342bc
MK
2808 (if (ediff-buffer-live-p ediff-ancestor-buffer)
2809 (ediff-remove-flags-from-buffer
2810 ediff-ancestor-buffer
2811 (ediff-get-diff-overlay n 'Ancestor)))
475f9031 2812 ))
475f9031
KH
2813 (setq ediff-highlighting-style nil)
2814
2815 ;; unhighlight fine diffs
2816 (ediff-set-fine-diff-properties ediff-current-difference 'default)
651342bc 2817 (run-hooks 'ediff-unselect-hook))))
475f9031
KH
2818
2819
2820;; Unselects prev diff and selects a new one, if FLAG has value other than
2821;; 'select-only or 'unselect-only. If FLAG is 'select-only, the
2822;; next difference is selected, but the current selection is not
2823;; unselected. If FLAG is 'unselect-only then the current selection is
2824;; unselected, but the next one is not selected. If NO-RECENTER is non-nil,
2825;; don't recenter buffers after selecting/unselecting.
475f9031 2826(defun ediff-unselect-and-select-difference (n &optional flag no-recenter)
41d25ad0
KH
2827 (let ((ediff-current-difference n))
2828 (or no-recenter
2829 (ediff-recenter 'no-rehighlight)))
475f9031 2830
41d25ad0
KH
2831 (let ((control-buf ediff-control-buffer))
2832 (unwind-protect
475f9031
KH
2833 (progn
2834 (or (eq flag 'select-only)
2835 (ediff-unselect-difference ediff-current-difference))
2836
475f9031
KH
2837 (or (eq flag 'unselect-only)
2838 (ediff-select-difference n))
2839 (setq ediff-current-difference n)
2840 ) ; end protected section
2841
e756eb9f 2842 (ediff-with-current-buffer control-buf (ediff-refresh-mode-lines))
475f9031
KH
2843 )))
2844
2845
2846(defun ediff-read-file-name (prompt default-dir default-file)
2847; This is a modified version of a similar function in `emerge.el'.
2848; PROMPT should not have trailing ': ', so that it can be modified
2849; according to context.
2850; If default-file is set, it should be used as the default value.
2851; If default-dir is non-nil, use it as the default directory.
2852; Otherwise, use the value of Emacs' variable `default-directory.'
2853
2854 ;; hack default-dir if it is not set
2855 (setq default-dir
2856 (file-name-as-directory
651342bc 2857 (ediff-abbreviate-file-name
475f9031
KH
2858 (expand-file-name (or default-dir
2859 (and default-file
2860 (file-name-directory default-file))
2861 default-directory)))))
2862
2863 ;; strip the directory from default-file
2864 (if default-file
2865 (setq default-file (file-name-nondirectory default-file)))
2866 (if (string= default-file "")
2867 (setq default-file nil))
2868
2869 (let (f)
2870 (setq f (expand-file-name
2871 (read-file-name
bbe6126c 2872 (format "%s%s "
475f9031 2873 prompt
bbe6126c
MK
2874 (cond (default-file
2875 (concat " (default " default-file "):"))
bbe6126c 2876 (t (concat " (default " default-dir "):"))))
475f9031 2877 default-dir
bbe6126c 2878 (or default-file default-dir)
41d25ad0 2879 t ; must match, no-confirm
475f9031
KH
2880 (if default-file (file-name-directory default-file))
2881 )
2882 default-dir
2883 ))
2884 ;; If user enters a directory name, expand the default file in that
2885 ;; directory. This allows the user to enter a directory name for the
2886 ;; B-file and diff against the default-file in that directory instead
2887 ;; of a DIRED listing!
2888 (if (and (file-directory-p f) default-file)
2889 (setq f (expand-file-name
2890 (file-name-nondirectory default-file) f)))
2891 f))
2892
4ae69eac
MK
2893;; If PREFIX is given, then it is used as a prefix for the temp file
2894;; name. Otherwise, `ediff_' is used. If FILE is given, use this
475f9031 2895;; file and don't create a new one.
4ae69eac
MK
2896;; On MS-DOS, make sure the prefix isn't longer than 7 characters, or
2897;; else `make-temp-name' isn't guaranteed to return a unique filename.
41d25ad0
KH
2898;; Also, save buffer from START to END in the file.
2899;; START defaults to (point-min), END to (point-max)
651342bc 2900(defun ediff-make-temp-file (buff &optional prefix given-file start end)
4ae69eac
MK
2901 (let ((p (or prefix "ediff"))
2902 f)
2903 (if (and (eq system-type 'ms-dos) (> (length p) 7))
2904 (setq p (substring p 0 7)))
2905
2906 (setq f (concat ediff-temp-file-prefix p)
2907 f (cond (given-file)
2908 ((find-file-name-handler f 'find-file-noselect)
2909 ;; to thwart file handlers in write-region, e.g., if file
2910 ;; name ends with .Z or .gz
2911 ;; This is needed so that patches produced by ediff will
2912 ;; have more meaningful names
2913 (make-temp-name f))
2914 ;; Prefix is most often the same as the file name for the
2915 ;; variant. Here we are trying to use the original file name
2916 ;; but in the temp directory.
2917 ((and prefix (not (file-exists-p f))) f)
2918 ;; If a file with the orig name exists, add some random stuff
2919 ;; to it.
2920 (t (make-temp-name f))))
2921
475f9031 2922 ;; create the file
e756eb9f 2923 (ediff-with-current-buffer buff
651342bc
MK
2924 (write-region (if start start (point-min))
2925 (if end end (point-max))
2926 f
2927 nil ; don't append---erase
2928 'no-message)
2929 (set-file-modes f ediff-temp-file-mode)
92c51e07 2930 (ediff-convert-standard-filename (expand-file-name f)))))
475f9031
KH
2931
2932;; Quote metacharacters (using \) when executing diff in Unix, but not in
2933;; EMX OS/2
651342bc
MK
2934;;(defun ediff-protect-metachars (str)
2935;; (or (memq system-type '(emx vax-vms axp-vms))
2936;; (let ((limit 0))
2937;; (while (string-match ediff-metachars str limit)
2938;; (setq str (concat (substring str 0 (match-beginning 0))
2939;; "\\"
2940;; (substring str (match-beginning 0))))
2941;; (setq limit (1+ (match-end 0))))))
2942;; str)
475f9031
KH
2943
2944;; Make sure the current buffer (for a file) has the same contents as the
2945;; file on disk, and attempt to remedy the situation if not.
2946;; Signal an error if we can't make them the same, or the user doesn't want
2947;; to do what is necessary to make them the same.
bbe6126c 2948;; Also, Ediff always offers to revert obsolete buffers, whether they
475f9031
KH
2949;; are modified or not.
2950(defun ediff-verify-file-buffer (&optional file-magic)
2951 ;; First check if the file has been modified since the buffer visited it.
2952 (if (verify-visited-file-modtime (current-buffer))
2953 (if (buffer-modified-p)
2954 ;; If buffer is not obsolete and is modified, offer to save
2955 (if (yes-or-no-p
bbe6126c 2956 (format "Buffer out of sync with visited file. Save file %s? "
475f9031 2957 buffer-file-name))
bbe6126c 2958 (condition-case nil
475f9031 2959 (save-buffer)
bbe6126c
MK
2960 (error
2961 (beep)
2962 (message "Couldn't save %s" buffer-file-name)))
2963 (error "Buffer is out of sync for file %s" buffer-file-name))
475f9031
KH
2964 ;; If buffer is not obsolete and is not modified, do nothing
2965 nil)
2966 ;; If buffer is obsolete, offer to revert
2967 (if (yes-or-no-p
bbe6126c 2968 (format "Buffer is out of sync with visited file. REVERT file %s? "
475f9031
KH
2969 buffer-file-name))
2970 (progn
2971 (if file-magic
2972 (erase-buffer))
2973 (revert-buffer t t))
2974 (error "Buffer out of sync for file %s" buffer-file-name))))
2975
2976
bd698e98
MK
2977(defun ediff-file-compressed-p (file)
2978 (require 'jka-compr)
2979 (string-match (jka-compr-build-file-regexp) file))
2980
2981(defun ediff-filename-magic-p (file)
2982 (or (ediff-file-compressed-p file)
2983 (ediff-file-remote-p file)))
2984
2985
475f9031
KH
2986(defun ediff-save-buffer (arg)
2987 "Safe way of saving buffers A, B, C, and the diff output.
2988`wa' saves buffer A, `wb' saves buffer B, `wc' saves buffer C,
651342bc
MK
2989and `wd' saves the diff output.
2990
2991With prefix argument, `wd' saves plain diff output.
2992Without an argument, it saves customized diff argument, if available
2993\(and plain output, if customized output was not generated\)."
475f9031 2994 (interactive "P")
651342bc
MK
2995 (ediff-barf-if-not-control-buffer)
2996 (ediff-compute-custom-diffs-maybe)
e756eb9f 2997 (ediff-with-current-buffer
41d25ad0
KH
2998 (cond ((memq last-command-char '(?a ?b ?c))
2999 (ediff-get-buffer
3000 (ediff-char-to-buftype last-command-char)))
3001 ((eq last-command-char ?d)
651342bc
MK
3002 (message "Saving diff output ...")
3003 (sit-for 1) ; let the user see the message
3004 (cond ((and arg (ediff-buffer-live-p ediff-diff-buffer))
3005 ediff-diff-buffer)
3006 ((ediff-buffer-live-p ediff-custom-diff-buffer)
3007 ediff-custom-diff-buffer)
3008 ((ediff-buffer-live-p ediff-diff-buffer)
3009 ediff-diff-buffer)
3010 (t (error "Output from `diff' not found"))))
3011 )
41d25ad0 3012 (save-buffer)))
651342bc
MK
3013
3014(defun ediff-compute-custom-diffs-maybe ()
4ae69eac
MK
3015 (let ((buf-A-file-name (buffer-file-name ediff-buffer-A))
3016 (buf-B-file-name (buffer-file-name ediff-buffer-B))
3017 file-A file-B)
3018 (if (stringp buf-A-file-name)
3019 (setq buf-A-file-name (file-name-nondirectory buf-A-file-name)))
3020 (if (stringp buf-B-file-name)
3021 (setq buf-B-file-name (file-name-nondirectory buf-B-file-name)))
3022 (setq file-A (ediff-make-temp-file ediff-buffer-A buf-A-file-name)
3023 file-B (ediff-make-temp-file ediff-buffer-B buf-B-file-name))
3024
3025 (or (ediff-buffer-live-p ediff-custom-diff-buffer)
3026 (setq ediff-custom-diff-buffer
3027 (get-buffer-create
3028 (ediff-unique-buffer-name "*ediff-custom-diff" "*"))))
3029 (ediff-exec-process
3030 ediff-custom-diff-program ediff-custom-diff-buffer 'synchronize
3031 ediff-custom-diff-options file-A file-B)
3032 (delete-file file-A)
3033 (delete-file file-B)
3034 ))
651342bc
MK
3035
3036(defun ediff-show-diff-output (arg)
3037 (interactive "P")
3038 (ediff-barf-if-not-control-buffer)
3039 (ediff-compute-custom-diffs-maybe)
3040 (save-excursion
3041 (ediff-skip-unsuitable-frames ' ok-unsplittable))
3042 (let ((buf (cond ((and arg (ediff-buffer-live-p ediff-diff-buffer))
3043 ediff-diff-buffer)
3044 ((ediff-buffer-live-p ediff-custom-diff-buffer)
3045 ediff-custom-diff-buffer)
3046 ((ediff-buffer-live-p ediff-diff-buffer)
3047 ediff-diff-buffer)
3048 (t
3049 (beep)
3050 (message "Output from `diff' not found")
3051 nil))))
3052 (if buf
3053 (progn
e756eb9f 3054 (ediff-with-current-buffer buf
651342bc
MK
3055 (goto-char (point-min)))
3056 (switch-to-buffer buf)
3057 (raise-frame (selected-frame)))))
3058 (if (frame-live-p ediff-control-frame)
3059 (ediff-reset-mouse ediff-control-frame))
3060 (if (window-live-p ediff-control-window)
3061 (select-window ediff-control-window)))
92c51e07
MK
3062
3063
3064(defun ediff-inferior-compare-regions ()
3065 "Compare regions in an active Ediff session.
3066Like ediff-regions-linewise but is called from under an active Ediff session on
3067the files that belong to that session.
3068
3069After quitting the session invoked via this function, type C-l to the parent
3070Ediff Control Panel to restore highlighting."
3071 (interactive)
3072 (let ((answer "")
3073 (possibilities (list ?A ?B ?C))
bf5d92c5 3074 (zmacs-regions t)
ddc90f39 3075 (ctl-buf (current-buffer))
bf5d92c5 3076 quit-now
92c51e07
MK
3077 begA begB endA endB bufA bufB)
3078
3079 (cond ((ediff-merge-job)
3080 (setq bufB ediff-buffer-C)
ddc90f39
MK
3081 (while (cond ((eq answer ?A)
3082 (setq bufA ediff-buffer-A
3083 possibilities '(?B))
92c51e07 3084 nil)
ddc90f39
MK
3085 ((eq answer ?B)
3086 (setq bufA ediff-buffer-B
3087 possibilities '(?A))
92c51e07
MK
3088 nil)
3089 ((equal answer ""))
3090 (t (beep 1)
bf5d92c5 3091 (message "Valid values are A or B")
92c51e07
MK
3092 (sit-for 2)
3093 t))
3094 (let ((cursor-in-echo-area t))
3095 (message "Which buffer to compare to the merge buffer (A/B)? ")
ddc90f39 3096 (setq answer (capitalize (read-char-exclusive))))))
92c51e07
MK
3097
3098 ((ediff-3way-comparison-job)
3099 (while (cond ((memq answer possibilities)
3100 (setq possibilities (delq answer possibilities))
3101 (setq bufA
3102 (eval
e756eb9f
MK
3103 (ediff-get-symbol-from-alist
3104 answer ediff-buffer-alist)))
92c51e07
MK
3105 nil)
3106 ((equal answer ""))
3107 (t (beep 1)
3108 (message
bf5d92c5 3109 "Valid values are %s"
92c51e07
MK
3110 (mapconcat 'char-to-string possibilities " or "))
3111 (sit-for 2)
3112 t))
3113 (let ((cursor-in-echo-area t))
3114 (message "Enter the 1st buffer you want to compare (%s): "
3115 (mapconcat 'char-to-string possibilities "/"))
3116 (setq answer (capitalize (read-char-exclusive)))))
3117 (setq answer "") ; silence error msg
3118 (while (cond ((memq answer possibilities)
3119 (setq possibilities (delq answer possibilities))
3120 (setq bufB
3121 (eval
e756eb9f
MK
3122 (ediff-get-symbol-from-alist
3123 answer ediff-buffer-alist)))
92c51e07
MK
3124 nil)
3125 ((equal answer ""))
3126 (t (beep 1)
3127 (message
bf5d92c5 3128 "Valid values are %s"
92c51e07
MK
3129 (mapconcat 'char-to-string possibilities " or "))
3130 (sit-for 2)
3131 t))
3132 (let ((cursor-in-echo-area t))
3133 (message "Enter the 2nd buffer you want to compare (%s): "
3134 (mapconcat 'char-to-string possibilities "/"))
3135 (setq answer (capitalize (read-char-exclusive))))))
3136 (t ; 2way comparison
3137 (setq bufA ediff-buffer-A
ddc90f39
MK
3138 bufB ediff-buffer-B
3139 possibilities nil)))
92c51e07 3140
e756eb9f 3141 (ediff-with-current-buffer bufA
bf5d92c5
MK
3142 (or (mark t)
3143 (error "You forgot to specify a region in buffer %s" (buffer-name)))
92c51e07
MK
3144 (setq begA (region-beginning)
3145 endA (region-end))
3146 (goto-char begA)
3147 (beginning-of-line)
3148 (setq begA (point))
3149 (goto-char endA)
3150 (end-of-line)
3151 (or (eobp) (forward-char)) ; include the newline char
3152 (setq endA (point)))
e756eb9f 3153 (ediff-with-current-buffer bufB
bf5d92c5
MK
3154 (or (mark t)
3155 (error "You forgot to specify a region in buffer %s" (buffer-name)))
92c51e07
MK
3156 (setq begB (region-beginning)
3157 endB (region-end))
3158 (goto-char begB)
3159 (beginning-of-line)
3160 (setq begB (point))
3161 (goto-char endB)
3162 (end-of-line)
3163 (or (eobp) (forward-char)) ; include the newline char
3164 (setq endB (point)))
3165
3166 (ediff-unselect-and-select-difference
3167 ediff-current-difference 'unselect-only)
3168 (ediff-paint-background-regions 'unhighlight)
3169
e756eb9f 3170 (ediff-with-current-buffer bufA
bf5d92c5
MK
3171 (goto-char begA)
3172 (set-mark endA)
3173 (narrow-to-region begA endA)
3174 ;; (ediff-activate-mark)
3175 )
3176 ;; (sit-for 0)
e756eb9f 3177 (ediff-with-current-buffer bufB
bf5d92c5
MK
3178 (goto-char begB)
3179 (set-mark endB)
3180 (narrow-to-region begB endB)
3181 ;; (ediff-activate-mark)
3182 )
3183 ;; (sit-for 0)
3184
ddc90f39
MK
3185 ;; At this point, possibilities contains either the window char A/B/C
3186 ;; that was not selected, or it is nil. We delete the window that is not
3187 ;; selected.
3188 (if possibilities
e756eb9f 3189 (ediff-with-current-buffer ctl-buf
ddc90f39 3190 (let* ((wind-to-delete (eval
e756eb9f
MK
3191 (ediff-get-symbol-from-alist
3192 (car possibilities)
3193 ediff-window-alist)))
ddc90f39
MK
3194 (frame (window-frame wind-to-delete)))
3195 (delete-window wind-to-delete)
3196 (select-frame frame)
3197 (balance-windows))))
bf5d92c5 3198 (or (y-or-n-p
ddc90f39 3199 "Please check regions selected for comparison. Continue? ")
bf5d92c5
MK
3200 (setq quit-now t))
3201
e756eb9f 3202 (ediff-with-current-buffer bufA
bf5d92c5 3203 (widen))
e756eb9f 3204 (ediff-with-current-buffer bufB
bf5d92c5
MK
3205 (widen))
3206 (if quit-now
e756eb9f 3207 (ediff-with-current-buffer ctl-buf
ddc90f39
MK
3208 (ediff-recenter)
3209 (sit-for 0)
3210 (error "All right. Make up your mind and come back...")))
bf5d92c5 3211
92c51e07
MK
3212 (ediff-regions-internal
3213 bufA begA endA bufB begB endB
ddc90f39 3214 nil ; setup-hook
92c51e07 3215 'ediff-regions-linewise ; job name
ddc90f39
MK
3216 nil ; no word mode
3217 ;; setup param to pass to ediff-setup
3218 (list (cons 'ediff-split-window-function ediff-split-window-function)))
92c51e07 3219 ))
651342bc 3220
475f9031
KH
3221
3222
41d25ad0 3223(defun ediff-remove-flags-from-buffer (buffer overlay)
e756eb9f 3224 (ediff-with-current-buffer buffer
41d25ad0 3225 (let ((inhibit-read-only t))
475f9031
KH
3226 (if ediff-xemacs-p
3227 (ediff-overlay-put overlay 'begin-glyph nil)
41d25ad0 3228 (ediff-overlay-put overlay 'before-string nil))
475f9031
KH
3229
3230 (if ediff-xemacs-p
3231 (ediff-overlay-put overlay 'end-glyph nil)
41d25ad0 3232 (ediff-overlay-put overlay 'after-string nil))
475f9031
KH
3233 )))
3234
3235
3236
475f9031 3237(defun ediff-place-flags-in-buffer (buf-type buffer ctl-buffer diff)
e756eb9f 3238 (ediff-with-current-buffer buffer
475f9031
KH
3239 (ediff-place-flags-in-buffer1 buf-type ctl-buffer diff)))
3240
3241
3242(defun ediff-place-flags-in-buffer1 (buf-type ctl-buffer diff-no)
e756eb9f 3243 (let* ((curr-overl (ediff-with-current-buffer ctl-buffer
475f9031 3244 (ediff-get-diff-overlay diff-no buf-type)))
475f9031 3245 (before (ediff-get-diff-posn buf-type 'beg diff-no ctl-buffer))
41d25ad0 3246 after beg-of-line flag)
475f9031
KH
3247
3248 ;; insert flag before the difference
3249 (goto-char before)
3250 (setq beg-of-line (bolp))
3251
e756eb9f 3252 (setq flag (ediff-with-current-buffer ctl-buffer
41d25ad0
KH
3253 (if (eq ediff-highlighting-style 'ascii)
3254 (if beg-of-line
3255 ediff-before-flag-bol ediff-before-flag-mol))))
475f9031
KH
3256
3257 ;; insert the flag itself
3258 (if ediff-xemacs-p
3259 (ediff-overlay-put curr-overl 'begin-glyph flag)
41d25ad0 3260 (ediff-overlay-put curr-overl 'before-string flag))
475f9031
KH
3261
3262 ;; insert the flag after the difference
3263 ;; `after' must be set here, after the before-flag was inserted
3264 (setq after (ediff-get-diff-posn buf-type 'end diff-no ctl-buffer))
3265 (goto-char after)
3266 (setq beg-of-line (bolp))
3267
e756eb9f 3268 (setq flag (ediff-with-current-buffer ctl-buffer
41d25ad0
KH
3269 (if (eq ediff-highlighting-style 'ascii)
3270 (if beg-of-line
3271 ediff-after-flag-eol ediff-after-flag-mol))))
475f9031
KH
3272
3273 ;; insert the flag itself
3274 (if ediff-xemacs-p
475f9031 3275 (ediff-overlay-put curr-overl 'end-glyph flag)
41d25ad0 3276 (ediff-overlay-put curr-overl 'after-string flag))
475f9031
KH
3277 ))
3278
3279
bbe6126c
MK
3280;; Returns positions of difference sectors in the BUF-TYPE buffer.
3281;; BUF-TYPE should be a symbol -- `A', `B', or `C'.
3282;; POS is either `beg' or `end'--it specifies whether you want the position at
3283;; the beginning of a difference or at the end.
3284;;
3285;; The optional argument N says which difference (default:
3286;; `ediff-current-difference'). N is the internal difference number (1- what
3287;; the user sees). The optional argument CONTROL-BUF says
3288;; which control buffer is in effect in case it is not the current
3289;; buffer.
475f9031 3290(defun ediff-get-diff-posn (buf-type pos &optional n control-buf)
475f9031
KH
3291 (let (diff-overlay)
3292 (or control-buf
3293 (setq control-buf (current-buffer)))
3294
e756eb9f 3295 (ediff-with-current-buffer control-buf
475f9031
KH
3296 (or n (setq n ediff-current-difference))
3297 (if (or (< n 0) (>= n ediff-number-of-differences))
3298 (if (> ediff-number-of-differences 0)
bbe6126c
MK
3299 (error ediff-BAD-DIFF-NUMBER
3300 this-command (1+ n) ediff-number-of-differences)
4ae69eac 3301 (error ediff-NO-DIFFERENCES)))
475f9031 3302 (setq diff-overlay (ediff-get-diff-overlay n buf-type)))
651342bc 3303 (if (not (ediff-buffer-live-p (ediff-overlay-buffer diff-overlay)))
4ae69eac 3304 (error ediff-KILLED-VITAL-BUFFER))
475f9031
KH
3305 (if (eq pos 'beg)
3306 (ediff-overlay-start diff-overlay)
3307 (ediff-overlay-end diff-overlay))
3308 ))
3309
3310
92c51e07
MK
3311;; Restore highlighting to what it should be according to ediff-use-faces,
3312;; ediff-highlighting-style, and ediff-highlight-all-diffs variables.
3313(defun ediff-restore-highlighting (&optional ctl-buf)
e756eb9f 3314 (ediff-with-current-buffer (or ctl-buf (current-buffer))
92c51e07
MK
3315 (if (and (ediff-has-face-support-p)
3316 ediff-use-faces
3317 ediff-highlight-all-diffs)
3318 (ediff-paint-background-regions))
3319 (ediff-select-difference ediff-current-difference)))
475f9031 3320
475f9031
KH
3321
3322
3323;; null out difference overlays so they won't slow down future
3324;; editing operations
3325;; VEC is either a difference vector or a fine-diff vector
3326(defun ediff-clear-diff-vector (vec-var &optional fine-diffs-also)
3327 (if (vectorp (symbol-value vec-var))
3328 (mapcar (function
3329 (lambda (elt)
3330 (ediff-delete-overlay
3331 (ediff-get-diff-overlay-from-diff-record elt))
3332 (if fine-diffs-also
3333 (ediff-clear-fine-diff-vector elt))
3334 ))
3335 (symbol-value vec-var)))
3336 ;; allow them to be garbage collected
3337 (set vec-var nil))
651342bc 3338
475f9031
KH
3339
3340\f
3341;;; Misc
3342
475f9031
KH
3343;; In Emacs, this just makes overlay. In the future, when Emacs will start
3344;; supporting sticky overlays, this function will make a sticky overlay.
3345;; BEG and END are expressions telling where overlay starts.
3346;; If they are numbers or buffers, then all is well. Otherwise, they must
3347;; be expressions to be evaluated in buffer BUF in order to get the overlay
3348;; bounds.
3349;; If BUFF is not a live buffer, then return nil; otherwise, return the
3350;; newly created overlay.
3351(defun ediff-make-bullet-proof-overlay (beg end buff)
3352 (if (ediff-buffer-live-p buff)
3353 (let (overl)
e756eb9f 3354 (ediff-with-current-buffer buff
475f9031
KH
3355 (or (number-or-marker-p beg)
3356 (setq beg (eval beg)))
3357 (or (number-or-marker-p end)
3358 (setq end (eval end)))
4ae69eac
MK
3359 (setq overl
3360 (if ediff-xemacs-p
3361 (make-extent beg end buff)
bbe6126c 3362 ;; advance front and rear of the overlay
4ae69eac 3363 (make-overlay beg end buff nil 'rear-advance)))
475f9031 3364
bbe6126c
MK
3365 ;; never detach
3366 (ediff-overlay-put
3367 overl (if ediff-emacs-p 'evaporate 'detachable) nil)
3368 ;; make vip-minibuffer-overlay open-ended
3369 ;; In emacs, it is made open ended at creation time
3370 (if ediff-xemacs-p
3371 (progn
3372 (ediff-overlay-put overl 'start-open nil)
3373 (ediff-overlay-put overl 'end-open nil)))
651342bc 3374 (ediff-overlay-put overl 'ediff-diff-num 0)
475f9031 3375 overl))))
41d25ad0 3376
475f9031 3377
475f9031
KH
3378;; Like other-buffer, but prefers visible buffers and ignores temporary or
3379;; other insignificant buffers (those beginning with "^[ *]").
3380;; Gets one arg--buffer name or a list of buffer names (it won't return
3381;; these buffers).
bd698e98
MK
3382(defun ediff-other-buffer (buff-lst)
3383 (or (listp buff-lst) (setq buff-lst (list buff-lst)))
41d25ad0 3384 (let* ((frame-buffers (buffer-list))
bd698e98
MK
3385 (buff-name-list
3386 (mapcar
3387 (function (lambda (b)
3388 (cond ((stringp b) b)
3389 ((bufferp b) (buffer-name b)))))
3390 buff-lst))
475f9031
KH
3391 (significant-buffers
3392 (mapcar
3393 (function (lambda (x)
bd698e98
MK
3394 (cond ((member (buffer-name x) buff-name-list) nil)
3395 ((not (ediff-get-visible-buffer-window x)) nil)
3396 ((string-match "^[ *]" (buffer-name x)) nil)
3397 ((memq (ediff-with-current-buffer x major-mode)
3398 '(dired-mode))
475f9031
KH
3399 nil)
3400 (t x))))
41d25ad0 3401 frame-buffers))
475f9031
KH
3402 (buffers (delq nil significant-buffers))
3403 less-significant-buffers)
3404
3405 (cond (buffers (car buffers))
3406 ;; try also buffers that are not displayed in windows
3407 ((setq less-significant-buffers
3408 (delq nil
3409 (mapcar
3410 (function
3411 (lambda (x)
bd698e98 3412 (cond ((member (buffer-name x) buff-name-list) nil)
475f9031 3413 ((string-match "^[ *]" (buffer-name x)) nil)
bd698e98
MK
3414 ((memq
3415 (ediff-with-current-buffer x major-mode)
3416 '(dired-mode))
3417 nil)
475f9031 3418 (t x))))
41d25ad0 3419 frame-buffers)))
475f9031
KH
3420 (car less-significant-buffers))
3421 (t (other-buffer (current-buffer))))
3422 ))
3423
3424
3425;; Construct a unique buffer name.
3426;; The first one tried is prefixsuffix, then prefix<2>suffix,
3427;; prefix<3>suffix, etc.
3428(defun ediff-unique-buffer-name (prefix suffix)
3429 (if (null (get-buffer (concat prefix suffix)))
3430 (concat prefix suffix)
3431 (let ((n 2))
3432 (while (get-buffer (format "%s<%d>%s" prefix n suffix))
3433 (setq n (1+ n)))
3434 (format "%s<%d>%s" prefix n suffix))))
3435
3436
475f9031
KH
3437(defun ediff-submit-report ()
3438 "Submit bug report on Ediff."
3439 (interactive)
651342bc 3440 (ediff-barf-if-not-control-buffer)
475f9031
KH
3441 (let ((reporter-prompt-for-summary-p t)
3442 (ctl-buf ediff-control-buffer)
41d25ad0 3443 (ediff-device-type (ediff-device-type))
475f9031
KH
3444 varlist salutation buffer-name)
3445 (setq varlist '(ediff-diff-program ediff-diff-options
3446 ediff-patch-program ediff-patch-options
3447 ediff-shell
3448 ediff-use-faces
3449 ediff-auto-refine ediff-highlighting-style
3450 ediff-buffer-A ediff-buffer-B ediff-control-buffer
3451 ediff-forward-word-function
3452 ediff-control-frame
3453 ediff-control-frame-parameters
3454 ediff-control-frame-position-function
3455 ediff-prefer-iconified-control-frame
3456 ediff-window-setup-function
3457 ediff-split-window-function
3458 ediff-job-name
3459 ediff-word-mode
3460 buffer-name
41d25ad0 3461 ediff-device-type
475f9031
KH
3462 ))
3463 (setq salutation "
3464Congratulations! You may have unearthed a bug in Ediff!
3465
3466Please make a concise and accurate summary of what happened
3467and mail it to the address above.
3468-----------------------------------------------------------
3469")
3470
3471 (ediff-skip-unsuitable-frames)
41d25ad0 3472 (ediff-reset-mouse)
475f9031
KH
3473
3474 (switch-to-buffer ediff-msg-buffer)
3475 (erase-buffer)
3476 (delete-other-windows)
3477 (insert "
3478Please read this first:
3479----------------------
3480
3481Some ``bugs'' may actually be no bugs at all. For instance, if you are
3482reporting that certain difference regions are not matched as you think they
3483should, this is most likely due to the way Unix diff program decides what
3484constitutes a difference region. Ediff is an Emacs interface to diff, and
3485it has nothing to do with those decisions---it only takes the output from
3486diff and presents it in a way that is better suited for human browsing and
3487manipulation.
3488
3489If Emacs happens to dump core, this is NOT an Ediff problem---it is
3490an Emacs bug. Report this to Emacs maintainers.
3491
3492Another popular topic for reports is compilation messages. Because Ediff
3493interfaces to several other packages and runs under Emacs and XEmacs,
3494byte-compilation may produce output like this:
3495
3496 While compiling toplevel forms in file ediff.el:
3497 ** reference to free variable pm-color-alist
3498 ........................
3499 While compiling the end of the data:
3500 ** The following functions are not known to be defined:
41d25ad0 3501 ediff-valid-color-p, ediff-set-face,
475f9031
KH
3502 ........................
3503
3504These are NOT errors, but inevitable warnings, which ought to be ignored.
3505
3506Please do not report those and similar things. However, comments and
3507suggestions are always welcome.
3508
3509Mail anyway? (y or n) ")
3510
3511 (if (y-or-n-p "Mail anyway? ")
3512 (progn
3513 (if (ediff-buffer-live-p ctl-buf)
3514 (set-buffer ctl-buf))
3515 (setq buffer-name (buffer-name))
3516 (require 'reporter)
3517 (reporter-submit-bug-report "kifer@cs.sunysb.edu"
3518 (ediff-version)
3519 varlist
3520 nil
3521 'delete-other-windows
3522 salutation))
3523 (bury-buffer)
3524 (beep 1)(message "Bug report aborted")
3525 (if (ediff-buffer-live-p ctl-buf)
e756eb9f 3526 (ediff-with-current-buffer ctl-buf
475f9031
KH
3527 (ediff-recenter 'no-rehighlight))))
3528 ))
3529
3530
475f9031
KH
3531(defun ediff-deactivate-mark ()
3532 (if ediff-xemacs-p
3533 (zmacs-deactivate-region)
3534 (deactivate-mark)))
bf5d92c5
MK
3535(defun ediff-activate-mark ()
3536 (if ediff-emacs-p
3537 (setq mark-active t)
3538 (zmacs-activate-region)))
475f9031
KH
3539
3540(cond ((fboundp 'nuke-selective-display)
3541 ;; XEmacs 19.12 has nuke-selective-display
3542 (fset 'ediff-nuke-selective-display 'nuke-selective-display))
3543 (t
3544 (defun ediff-nuke-selective-display ()
3545 (save-excursion
3546 (save-restriction
3547 (widen)
3548 (goto-char (point-min))
3549 (let ((mod-p (buffer-modified-p))
41d25ad0 3550 buffer-read-only end)
475f9031
KH
3551 (and (eq t selective-display)
3552 (while (search-forward "\^M" nil t)
3553 (end-of-line)
3554 (setq end (point))
3555 (beginning-of-line)
3556 (while (search-forward "\^M" end t)
3557 (delete-char -1)
3558 (insert "\^J"))))
3559 (set-buffer-modified-p mod-p)
3560 (setq selective-display nil)))))
3561 ))
3562
3563
41d25ad0 3564;; The next two are modified versions from emerge.el.
475f9031 3565;; VARS must be a list of symbols
41d25ad0
KH
3566;; ediff-save-variables returns an association list: ((var . val) ...)
3567(defsubst ediff-save-variables (vars)
3568 (mapcar (function (lambda (v) (cons v (symbol-value v))))
475f9031 3569 vars))
41d25ad0
KH
3570;; VARS is a list of variable symbols.
3571(defun ediff-restore-variables (vars assoc-list)
475f9031 3572 (while vars
41d25ad0
KH
3573 (set (car vars) (cdr (assoc (car vars) assoc-list)))
3574 (setq vars (cdr vars))))
651342bc 3575
41d25ad0
KH
3576(defun ediff-change-saved-variable (var value buf-type)
3577 (let* ((assoc-list
e756eb9f
MK
3578 (symbol-value (ediff-get-symbol-from-alist
3579 buf-type
3580 ediff-buffer-values-orig-alist)))
41d25ad0
KH
3581 (assoc-elt (assoc var assoc-list)))
3582 (if assoc-elt
3583 (setcdr assoc-elt value))))
3584
475f9031
KH
3585
3586;; must execute in control buf
3587(defun ediff-save-protected-variables ()
41d25ad0 3588 (setq ediff-buffer-values-orig-A
e756eb9f 3589 (ediff-with-current-buffer ediff-buffer-A
475f9031 3590 (ediff-save-variables ediff-protected-variables)))
41d25ad0 3591 (setq ediff-buffer-values-orig-B
e756eb9f 3592 (ediff-with-current-buffer ediff-buffer-B
475f9031
KH
3593 (ediff-save-variables ediff-protected-variables)))
3594 (if ediff-3way-comparison-job
41d25ad0 3595 (setq ediff-buffer-values-orig-C
e756eb9f 3596 (ediff-with-current-buffer ediff-buffer-C
651342bc
MK
3597 (ediff-save-variables ediff-protected-variables))))
3598 (if (ediff-buffer-live-p ediff-ancestor-buffer)
3599 (setq ediff-buffer-values-orig-Ancestor
e756eb9f 3600 (ediff-with-current-buffer ediff-ancestor-buffer
475f9031
KH
3601 (ediff-save-variables ediff-protected-variables)))))
3602
3603;; must execute in control buf
3604(defun ediff-restore-protected-variables ()
41d25ad0
KH
3605 (let ((values-A ediff-buffer-values-orig-A)
3606 (values-B ediff-buffer-values-orig-B)
651342bc
MK
3607 (values-C ediff-buffer-values-orig-C)
3608 (values-Ancestor ediff-buffer-values-orig-Ancestor))
e756eb9f 3609 (ediff-with-current-buffer ediff-buffer-A
651342bc 3610 (ediff-restore-variables ediff-protected-variables values-A))
e756eb9f 3611 (ediff-with-current-buffer ediff-buffer-B
651342bc
MK
3612 (ediff-restore-variables ediff-protected-variables values-B))
3613 (if ediff-3way-comparison-job
e756eb9f 3614 (ediff-with-current-buffer ediff-buffer-C
651342bc
MK
3615 (ediff-restore-variables ediff-protected-variables values-C)))
3616 (if (ediff-buffer-live-p ediff-ancestor-buffer)
e756eb9f 3617 (ediff-with-current-buffer ediff-ancestor-buffer
651342bc
MK
3618 (ediff-restore-variables ediff-protected-variables values-Ancestor)))
3619 ))
475f9031 3620
4ae69eac
MK
3621;; save BUFFER in FILE. used in hooks.
3622(defun ediff-save-buffer-in-file (buffer file)
e756eb9f 3623 (ediff-with-current-buffer buffer
4ae69eac
MK
3624 (write-file file)))
3625
475f9031
KH
3626
3627;;; Debug
3628
3629(ediff-defvar-local ediff-command-begin-time '(0 0 0) "")
3630
3631;; calculate time used by command
3632(defun ediff-calc-command-time ()
3633 (let ((end (current-time))
3634 micro sec)
3635 (setq micro
3636 (if (>= (nth 2 end) (nth 2 ediff-command-begin-time))
3637 (- (nth 2 end) (nth 2 ediff-command-begin-time))
3638 (+ (nth 2 end) (- 1000000 (nth 2 ediff-command-begin-time)))))
3639 (setq sec (- (nth 1 end) (nth 1 ediff-command-begin-time)))
3640 (or (equal ediff-command-begin-time '(0 0 0))
3641 (message "Elapsed time: %d second(s) + %d microsecond(s)" sec micro))))
3642
3643(defsubst ediff-save-time ()
3644 (setq ediff-command-begin-time (current-time)))
3645
3646(defun ediff-profile ()
3647 "Toggle profiling Ediff commands."
3648 (interactive)
651342bc 3649 (ediff-barf-if-not-control-buffer)
4ae69eac
MK
3650 (make-local-hook 'post-command-hook)
3651 (let ((pre-hook 'pre-command-hook)
3652 (post-hook 'post-command-hook))
651342bc
MK
3653 (if (not (equal ediff-command-begin-time '(0 0 0)))
3654 (progn (remove-hook pre-hook 'ediff-save-time)
3655 (remove-hook post-hook 'ediff-calc-command-time)
3656 (setq ediff-command-begin-time '(0 0 0))
3657 (message "Ediff profiling disabled"))
bbe6126c
MK
3658 (add-hook pre-hook 'ediff-save-time t t)
3659 (add-hook post-hook 'ediff-calc-command-time nil t)
651342bc 3660 (message "Ediff profiling enabled"))))
475f9031
KH
3661
3662(defun ediff-print-diff-vector (diff-vector-var)
3663 (princ (format "\n*** %S ***\n" diff-vector-var))
3664 (mapcar (function
3665 (lambda (overl-vec)
3666 (princ
3667 (format
3668 "Diff %d: \tOverlay: %S
3669\t\tFine diffs: %s
3670\t\tNo-fine-diff-flag: %S
3671\t\tState-of-diff:\t %S
3672\t\tState-of-merge:\t %S
3673"
3674 (1+ (ediff-overlay-get (aref overl-vec 0) 'ediff-diff-num))
3675 (aref overl-vec 0)
3676 ;; fine-diff-vector
3677 (if (= (length (aref overl-vec 1)) 0)
3678 "none\n"
3679 (mapconcat 'prin1-to-string
3680 (aref overl-vec 1) "\n\t\t\t "))
3681 (aref overl-vec 2) ; no fine diff flag
3682 (aref overl-vec 3) ; state-of-diff
3683 (aref overl-vec 4) ; state-of-merge
3684 ))))
3685 (eval diff-vector-var)))
3686
3687
3688
3689(defun ediff-debug-info ()
3690 (interactive)
651342bc 3691 (ediff-barf-if-not-control-buffer)
475f9031
KH
3692 (with-output-to-temp-buffer ediff-debug-buffer
3693 (princ (format "\nCtl buffer: %S\n" ediff-control-buffer))
651342bc
MK
3694 (ediff-print-diff-vector (intern "ediff-difference-vector-A"))
3695 (ediff-print-diff-vector (intern "ediff-difference-vector-B"))
3696 (ediff-print-diff-vector (intern "ediff-difference-vector-C"))
3697 (ediff-print-diff-vector (intern "ediff-difference-vector-Ancestor"))
475f9031
KH
3698 ))
3699
4ae69eac
MK
3700
3701;;; General utilities
3702
3703;; this uses comparison-func to decide who is a member
3704(defun ediff-member (elt lis comparison-func)
3705 (while (and lis (not (funcall comparison-func (car lis) elt)))
3706 (setq lis (cdr lis)))
3707 lis)
3708
3709;; this uses comparison-func to decide who is a member, and this determines how
3710;; intersection looks like
3711(defun ediff-intersection (lis1 lis2 comparison-func)
3712 (let ((result (list 'a)))
3713 (while lis1
3714 (if (ediff-member (car lis1) lis2 comparison-func)
3715 (nconc result (list (car lis1))))
3716 (setq lis1 (cdr lis1)))
3717 (cdr result)))
3718
3719
3720;; eliminates duplicates using comparison-func
3721(defun ediff-union (lis1 lis2 comparison-func)
3722 (let ((result (list 'a)))
3723 (while lis1
3724 (or (ediff-member (car lis1) (cdr result) comparison-func)
3725 (nconc result (list (car lis1))))
3726 (setq lis1 (cdr lis1)))
3727 (while lis2
3728 (or (ediff-member (car lis2) (cdr result) comparison-func)
3729 (nconc result (list (car lis2))))
3730 (setq lis2 (cdr lis2)))
3731 (cdr result)))
3732
3733;; eliminates duplicates using comparison-func
3734(defun ediff-set-difference (lis1 lis2 comparison-func)
3735 (let ((result (list 'a)))
3736 (while lis1
3737 (or (ediff-member (car lis1) (cdr result) comparison-func)
3738 (ediff-member (car lis1) lis2 comparison-func)
3739 (nconc result (list (car lis1))))
3740 (setq lis1 (cdr lis1)))
3741 (cdr result)))
3742
3743(defun ediff-copy-list (list)
3744 (if (consp list)
3745 ;;;(let ((res nil))
3746 ;;; (while (consp list) (push (pop list) res))
3747 ;;; (prog1 (nreverse res) (setcdr res list)))
3748 (let (res elt)
3749 (while (consp list)
3750 (setq elt (car list)
3751 res (cons elt res)
3752 list (cdr list)))
3753 (nreverse res))
3754 (car list)))
3755
3756
475f9031
KH
3757;; don't report error if version control package wasn't found
3758;;(ediff-load-version-control 'silent)
3759
651342bc 3760(run-hooks 'ediff-load-hook)
475f9031 3761
41d25ad0 3762
475f9031
KH
3763;;; Local Variables:
3764;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
3765;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
3766;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
475f9031
KH
3767;;; End:
3768
475f9031 3769;;; ediff-util.el ends here