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