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