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