* align.el:
[bpt/emacs.git] / lisp / ediff-merg.el
CommitLineData
475f9031 1;;; ediff-merg.el --- merging utilities
b578f267 2
0d30b337 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
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
475f9031 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
475f9031
KH
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
475f9031 22
3afbc435
PJ
23;;; Commentary:
24
b578f267 25;;; Code:
475f9031 26
ddc90f39 27
ddc90f39
MK
28;; compiler pacifier
29(defvar ediff-window-A)
30(defvar ediff-window-B)
31(defvar ediff-window-C)
32(defvar ediff-merge-window-share)
33(defvar ediff-window-config-saved)
34
35(eval-when-compile
8480ec72 36 (require 'ediff-util))
ddc90f39
MK
37;; end pacifier
38
475f9031
KH
39(require 'ediff-init)
40
1e70790f 41(defcustom ediff-quit-merge-hook 'ediff-maybe-save-and-delete-merge
9201cc28 42 "Hooks to run before quitting a merge job.
1e70790f
MK
43The most common use is to save and delete the merge buffer."
44 :type 'hook
45 :group 'ediff-merge)
46
bbe6126c 47
ddc90f39 48(defcustom ediff-default-variant 'combined
9201cc28 49 "The variant to be used as a default for buffer C in merging.
ddc90f39
MK
50Valid values are the symbols `default-A', `default-B', and `combined'."
51 :type '(radio (const default-A) (const default-B) (const combined))
52 :group 'ediff-merge)
475f9031 53
71296446 54(defcustom ediff-combination-pattern
086171bf 55 '("<<<<<<< variant A" A ">>>>>>> variant B" B "####### Ancestor" Ancestor "======= end")
9201cc28 56 "Pattern to be used for combining difference regions in buffers A and B.
71296446 57The value must be a list of the form
4601d7c4 58\(STRING1 bufspec1 STRING2 bufspec2 STRING3 bufspec3 STRING4)
086171bf
MK
59where bufspec is the symbol A, B, or Ancestor. For instance, if the value is
60'(STRING1 A STRING2 Ancestor STRING3 B STRING4) then the
61combined text will look like this:
475f9031
KH
62
63STRING1
64diff region from variant A
65STRING2
086171bf 66diff region from the ancestor
475f9031 67STRING3
086171bf
MK
68diff region from variant B
69STRING4
ddc90f39 70"
086171bf
MK
71 :type '(choice (list string symbol string symbol string)
72 (list string symbol string symbol string symbol string))
ddc90f39 73 :group 'ediff-merge)
475f9031 74
3af0304a 75(defcustom ediff-show-clashes-only nil
9201cc28 76 "If t, show only those diff regions where both buffers disagree with the ancestor.
475f9031 77This means that regions that have status prefer-A or prefer-B will be
4601d7c4 78skipped over. A value of nil means show all regions."
3af0304a
MK
79 :type 'boolean
80 :group 'ediff-merge
81 )
82(make-variable-buffer-local 'ediff-show-clashes-only)
83
84(defcustom ediff-skip-merge-regions-that-differ-from-default nil
9201cc28 85 "If t, show only the regions that have not been changed by the user.
3af0304a
MK
86A region is considered to have been changed if it is different from the current
87default (`default-A', `default-B', `combined') and it hasn't been marked as
88`prefer-A' or `prefer-B'.
71296446 89A region is considered to have been changed also when it is marked as
3af0304a
MK
90as `prefer-A', but is different from the corresponding difference region in
91Buffer A or if it is marked as `prefer-B' and is different from the region in
92Buffer B."
93 :type 'boolean
94 :group 'ediff-merge
95 )
96(make-variable-buffer-local 'ediff-skip-merge-regions-that-differ-from-default)
475f9031 97
e2de3a29 98;; check if there is no clash between the ancestor and one of the variants.
39bcfe5f 99;; if it is not a merge job then return true
e2de3a29 100(defsubst ediff-merge-region-is-non-clash (n)
39bcfe5f
MK
101 (if (ediff-merge-job)
102 (string-match "prefer" (or (ediff-get-state-of-merge n) ""))
103 t))
e2de3a29 104
8e41a31c
MK
105;; If ediff-show-clashes-only, check if there is no clash between the ancestor
106;; and one of the variants.
e2de3a29 107(defsubst ediff-merge-region-is-non-clash-to-skip (n)
8e41a31c 108 (and ediff-show-clashes-only
e2de3a29 109 (ediff-merge-region-is-non-clash n)))
8e41a31c 110
3af0304a
MK
111;; If ediff-skip-changed-regions, check if the merge region differs from
112;; the current default. If a region is different from the default, it means
113;; that the user has made determination as to how to merge for this particular
71296446 114;; region.
3af0304a
MK
115(defsubst ediff-skip-merge-region-if-changed-from-default-p (n)
116 (and ediff-skip-merge-regions-that-differ-from-default
117 (ediff-merge-changed-from-default-p n 'prefers-too)))
118
119
086171bf
MK
120(defun ediff-get-combined-region (n)
121 (let ((pattern-list ediff-combination-pattern)
122 (combo-region "")
123 (err-msg
124 "ediff-combination-pattern: Invalid format. Please consult the documentation")
50a07e18 125 region-delim region-spec)
086171bf
MK
126
127 (if (< (length pattern-list) 5)
128 (error err-msg))
129
130 (while (> (length pattern-list) 2)
131 (setq region-delim (nth 0 pattern-list)
132 region-spec (nth 1 pattern-list))
133 (or (and (stringp region-delim) (memq region-spec '(A B Ancestor)))
134 (error err-msg))
135
50a07e18 136 (condition-case nil
086171bf
MK
137 (setq combo-region
138 (concat combo-region
139 region-delim "\n"
71296446 140 (ediff-get-region-contents
086171bf
MK
141 n region-spec ediff-control-buffer)))
142 (error ""))
143 (setq pattern-list (cdr (cdr pattern-list)))
144 )
145
146 (setq region-delim (nth 0 pattern-list))
147 (or (stringp region-delim)
148 (error err-msg))
149 (setq combo-region (concat combo-region region-delim "\n"))
150 ))
151
152;;(defsubst ediff-make-combined-diff (regA regB)
153;; (concat (nth 0 ediff-combination-pattern) "\n"
154;; regA
155;; (nth 1 ediff-combination-pattern) "\n"
156;; regB
157;; (nth 2 ediff-combination-pattern) "\n"))
009650b3 158
475f9031
KH
159(defsubst ediff-set-state-of-all-diffs-in-all-buffers (ctl-buf)
160 (let ((n 0))
161 (while (< n ediff-number-of-differences)
162 (ediff-set-state-of-diff-in-all-buffers n ctl-buf)
163 (setq n (1+ n)))))
71296446 164
475f9031
KH
165(defun ediff-set-state-of-diff-in-all-buffers (n ctl-buf)
166 (let ((regA (ediff-get-region-contents n 'A ctl-buf))
167 (regB (ediff-get-region-contents n 'B ctl-buf))
168 (regC (ediff-get-region-contents n 'C ctl-buf)))
13340e24
KH
169 (cond ((and (string= regA regB) (string= regA regC))
170 (ediff-set-state-of-diff n 'A "=diff(B)")
171 (ediff-set-state-of-diff n 'B "=diff(C)")
172 (ediff-set-state-of-diff n 'C "=diff(A)"))
173 ((string= regA regB)
475f9031
KH
174 (ediff-set-state-of-diff n 'A "=diff(B)")
175 (ediff-set-state-of-diff n 'B "=diff(A)")
176 (ediff-set-state-of-diff n 'C nil))
177 ((string= regA regC)
178 (ediff-set-state-of-diff n 'A "=diff(C)")
179 (ediff-set-state-of-diff n 'C "=diff(A)")
180 (ediff-set-state-of-diff n 'B nil))
181 ((string= regB regC)
182 (ediff-set-state-of-diff n 'C "=diff(B)")
183 (ediff-set-state-of-diff n 'B "=diff(C)")
184 (ediff-set-state-of-diff n 'A nil))
185 ((string= regC (ediff-get-combined-region n))
186 (ediff-set-state-of-diff n 'A nil)
187 (ediff-set-state-of-diff n 'B nil)
188 (ediff-set-state-of-diff n 'C "=diff(A+B)"))
189 (t (ediff-set-state-of-diff n 'A nil)
190 (ediff-set-state-of-diff n 'B nil)
191 (ediff-set-state-of-diff n 'C nil)))
192 ))
71296446 193
13340e24 194(defun ediff-set-merge-mode ()
13340e24
KH
195 (normal-mode t)
196 (remove-hook 'local-write-file-hooks 'ediff-set-merge-mode))
c439fb30 197
71296446 198
475f9031
KH
199;; Go over all diffs starting with DIFF-NUM and copy regions into buffer C
200;; according to the state of the difference.
201;; Since ediff-copy-diff refuses to copy identical diff regions, there is
202;; no need to optimize ediff-do-merge any further.
203;;
204;; If re-merging, change state of merge in all diffs starting with
205;; DIFF-NUM, except those where the state is prefer-* or where it is
13340e24
KH
206;; `default-*' or `combined' but the buf C region appears to be modified
207;; since last set by default.
475f9031
KH
208(defun ediff-do-merge (diff-num &optional remerging)
209 (if (< diff-num 0) (setq diff-num 0))
210 (let ((n diff-num)
bbe6126c 211 ;;(default-state-of-merge (format "%S" ediff-default-variant))
13340e24 212 do-not-copy state-of-merge)
475f9031 213 (while (< n ediff-number-of-differences)
bbe6126c 214 (setq do-not-copy nil) ; reset after each cycle
475f9031
KH
215 (if (= (mod n 10) 0)
216 (message "%s buffers A & B into C ... region %d of %d"
217 (if remerging "Re-merging" "Merging")
218 n
219 ediff-number-of-differences))
71296446 220
475f9031 221 (setq state-of-merge (ediff-get-state-of-merge n))
475f9031
KH
222
223 (if remerging
50a07e18
MK
224 ;;(let ((reg-A (ediff-get-region-contents n 'A ediff-control-buffer))
225 ;; (reg-B (ediff-get-region-contents n 'B ediff-control-buffer))
226 ;; (reg-C (ediff-get-region-contents n 'C ediff-control-buffer)))
227 (let ()
71296446 228
bbe6126c 229 ;; if region was edited since it was first set by default
3af0304a
MK
230 (if (or (ediff-merge-changed-from-default-p n)
231 ;; was preferred
13340e24 232 (string-match "prefer" state-of-merge))
3af0304a 233 ;; then ignore
475f9031 234 (setq do-not-copy t))
71296446 235
475f9031 236 ;; change state of merge for this diff, if necessary
13340e24
KH
237 (if (and (string-match "\\(default\\|combined\\)" state-of-merge)
238 (not do-not-copy))
475f9031
KH
239 (ediff-set-state-of-merge
240 n (format "%S" ediff-default-variant)))
241 ))
71296446 242
475f9031 243 ;; state-of-merge may have changed via ediff-set-state-of-merge, so
13340e24 244 ;; check it once again
475f9031 245 (setq state-of-merge (ediff-get-state-of-merge n))
71296446 246
475f9031
KH
247 (or do-not-copy
248 (if (string= state-of-merge "combined")
249 ;; use n+1 because ediff-combine-diffs works via user numbering
250 ;; of diffs, which is 1+ to what ediff uses internally
251 (ediff-combine-diffs (1+ n) 'batch)
71296446 252 (ediff-copy-diff
13340e24 253 n (if (string-match "-A" state-of-merge) 'A 'B) 'C 'batch)))
475f9031
KH
254 (setq n (1+ n)))
255 (message "Merging buffers A & B into C ... Done")
256 ))
71296446 257
475f9031
KH
258
259(defun ediff-re-merge ()
3af0304a 260 "Remerge unmodified diff regions using a new default. Start with the current region."
475f9031
KH
261 (interactive)
262 (let* ((default-variant-alist
263 (list '("default-A") '("default-B") '("combined")))
264 (actual-alist
265 (delete (list (symbol-name ediff-default-variant))
266 default-variant-alist)))
267 (setq ediff-default-variant
268 (intern
71296446 269 (completing-read
3af0304a 270 (format "Current merge default is `%S'. New default: "
475f9031
KH
271 ediff-default-variant)
272 actual-alist nil 'must-match)))
273 (ediff-do-merge ediff-current-difference 'remerge)
274 (ediff-recenter)
275 ))
71296446 276
475f9031
KH
277(defun ediff-shrink-window-C (arg)
278 "Shrink window C to just one line.
279With a prefix argument, returns window C to its normal size.
280Used only for merging jobs."
281 (interactive "P")
282 (if (not ediff-merge-job)
283 (error "ediff-shrink-window-C can be used only for merging jobs"))
284 (cond ((eq arg '-) (setq arg -1))
285 ((not (numberp arg)) (setq arg nil)))
286 (cond ((null arg)
287 (let ((ediff-merge-window-share
288 (if (< (window-height ediff-window-C) 3)
289 ediff-merge-window-share 0)))
290 (setq ediff-window-config-saved "") ; force redisplay
291 (ediff-recenter 'no-rehighlight)))
292 ((and (< arg 0) (> (window-height ediff-window-C) 2))
293 (setq ediff-merge-window-share (* ediff-merge-window-share 0.9))
294 (setq ediff-window-config-saved "") ; force redisplay
295 (ediff-recenter 'no-rehighlight))
296 ((and (> arg 0) (> (window-height ediff-window-A) 2))
297 (setq ediff-merge-window-share (* ediff-merge-window-share 1.1))
298 (setq ediff-window-config-saved "") ; force redisplay
299 (ediff-recenter 'no-rehighlight))))
300
301
3af0304a 302;; N here is the user's region number. It is 1+ what Ediff uses internally.
475f9031
KH
303(defun ediff-combine-diffs (n &optional batch-invocation)
304 "Combine Nth diff regions of buffers A and B and place the combination in C.
3af0304a 305N is a prefix argument. If nil, combine the current difference regions.
4ae69eac
MK
306Combining is done according to the specifications in variable
307`ediff-combination-pattern'."
475f9031 308 (interactive "P")
4ae69eac 309 (setq n (if (numberp n) (1- n) ediff-current-difference))
71296446 310
50a07e18 311 (let (reg-combined)
086171bf
MK
312 ;;(setq regA (ediff-get-region-contents n 'A ediff-control-buffer)
313 ;; regB (ediff-get-region-contents n 'B ediff-control-buffer))
314 ;;(setq reg-combined (ediff-make-combined-diff regA regB))
315 (setq reg-combined (ediff-get-combined-region n))
71296446 316
475f9031 317 (ediff-copy-diff n nil 'C batch-invocation reg-combined))
4ae69eac 318 (or batch-invocation (ediff-jump-to-difference (1+ n))))
71296446 319
475f9031
KH
320
321;; Checks if the region in buff C looks like a combination of the regions
3af0304a 322;; in buffers A and B. Return a list (reg-a-beg reg-a-end reg-b-beg reg-b-end)
086171bf
MK
323;; These refer to where the delimiters for region A, B, Ancestor start and end
324;; in buffer C
475f9031
KH
325(defun ediff-looks-like-combined-merge (region-num)
326 (if ediff-merge-job
327 (let ((combined (string-match (regexp-quote "(A+B)")
328 (or (ediff-get-state-of-diff region-num 'C)
329 "")))
086171bf
MK
330 (mrgreg-beg (ediff-get-diff-posn 'C 'beg region-num))
331 (mrgreg-end (ediff-get-diff-posn 'C 'end region-num))
332 (pattern-list ediff-combination-pattern)
333 delim reg-beg reg-end delim-regs-list)
71296446 334
475f9031 335 (if combined
e756eb9f 336 (ediff-with-current-buffer ediff-buffer-C
086171bf
MK
337 (while pattern-list
338 (goto-char mrgreg-beg)
339 (setq delim (nth 0 pattern-list))
340 (search-forward delim mrgreg-end 'noerror)
341 (setq reg-beg (match-beginning 0))
342 (setq reg-end (match-end 0))
343 (if (and reg-beg reg-end)
344 (setq delim-regs-list
345 ;; in reverse
346 (cons reg-end (cons reg-beg delim-regs-list))))
347 (if (> (length pattern-list) 1)
348 (setq pattern-list (cdr (cdr pattern-list)))
349 (setq pattern-list nil))
350 )))
351
352 (reverse delim-regs-list)
475f9031 353 )))
3b90e5b8 354
937382fa 355(defvar state-of-merge) ; dynamic var
3af0304a
MK
356
357;; Check if the non-preferred merge has been modified since originally set.
358;; This affects only the regions that are marked as default-A/B or combined.
359;; If PREFERS-TOO is non-nil, then look at the regions marked as prefers-A/B as
360;; well.
361(defun ediff-merge-changed-from-default-p (diff-num &optional prefers-too)
362 (let ((reg-A (ediff-get-region-contents diff-num 'A ediff-control-buffer))
363 (reg-B (ediff-get-region-contents diff-num 'B ediff-control-buffer))
364 (reg-C (ediff-get-region-contents diff-num 'C ediff-control-buffer)))
365
366 (setq state-of-merge (ediff-get-state-of-merge diff-num))
71296446 367
3af0304a
MK
368 ;; if region was edited since it was first set by default
369 (or (and (string= state-of-merge "default-A")
370 (not (string= reg-A reg-C)))
371 (and (string= state-of-merge "default-B")
372 (not (string= reg-B reg-C)))
373 (and (string= state-of-merge "combined")
086171bf
MK
374 ;;(not (string= (ediff-make-combined-diff reg-A reg-B) reg-C)))
375 (not (string= (ediff-get-combined-region diff-num) reg-C)))
3af0304a
MK
376 (and prefers-too
377 (string= state-of-merge "prefer-A")
378 (not (string= reg-A reg-C)))
379 (and prefers-too
380 (string= state-of-merge "prefer-B")
381 (not (string= reg-B reg-C)))
382 )))
71296446 383
475f9031 384
b6178721
MK
385(provide 'ediff-merg)
386
387
92c51e07
MK
388;;; Local Variables:
389;;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
e756eb9f
MK
390;;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
391;;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
92c51e07
MK
392;;; End:
393
cbee283d 394;; arch-tag: 9b798cf9-02ba-487f-a62e-b63aa823dbfb
3afbc435 395;;; ediff-merg.el ends here