Mercurial > emacs
comparison lisp/smerge-mode.el @ 93445:87b6e6f4a207
(smerge-apply-resolution-patch): New fun.
(smerge-resolve): Add various resolution heuristics.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Mon, 31 Mar 2008 02:57:39 +0000 |
parents | a6d8268a0da6 |
children | 955774916817 |
comparison
equal
deleted
inserted
replaced
93444:3a3281d7f1dd | 93445:87b6e6f4a207 |
---|---|
405 (let ((beg (re-search-backward smerge-end-re nil t)) | 405 (let ((beg (re-search-backward smerge-end-re nil t)) |
406 (end (re-search-forward smerge-begin-re nil t))) | 406 (end (re-search-forward smerge-begin-re nil t))) |
407 (smerge-remove-props (or beg (point-min)) (or end (point-max))) | 407 (smerge-remove-props (or beg (point-min)) (or end (point-max))) |
408 (push event unread-command-events))))) | 408 (push event unread-command-events))))) |
409 | 409 |
410 (defun smerge-apply-resolution-patch (buf m0b m0e m3b m3e &optional m2b) | |
411 "Replace the conflict with a bunch of subconflicts. | |
412 BUF contains a plain diff between match-1 and match-3." | |
413 (let ((line 1) | |
414 (textbuf (current-buffer)) | |
415 (name1 (progn (goto-char m0b) | |
416 (buffer-substring (+ (point) 8) (line-end-position)))) | |
417 (name2 (when m2b (goto-char m2b) (forward-line -1) | |
418 (buffer-substring (+ (point) 8) (line-end-position)))) | |
419 (name3 (progn (goto-char m0e) (forward-line -1) | |
420 (buffer-substring (+ (point) 8) (line-end-position))))) | |
421 (smerge-remove-props m0b m0e) | |
422 (delete-region m3e m0e) | |
423 (delete-region m0b m3b) | |
424 (setq m3b m0b) | |
425 (setq m3e (- m3e (- m3b m0b))) | |
426 (goto-char m3b) | |
427 (with-current-buffer buf | |
428 (goto-char (point-min)) | |
429 (while (not (eobp)) | |
430 (if (not (looking-at "\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?\\([acd]\\)\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?$")) | |
431 (error "Unexpected patch hunk header: %s" | |
432 (buffer-substring (point) (line-end-position))) | |
433 (let* ((op (char-after (match-beginning 3))) | |
434 (startline (+ (string-to-number (match-string 1)) | |
435 ;; No clue why this is the way it is, but line | |
436 ;; numbers seem to be off-by-one for `a' ops. | |
437 (if (eq op ?a) 1 0))) | |
438 (endline (if (eq op ?a) startline | |
439 (1+ (if (match-end 2) | |
440 (string-to-number (match-string 2)) | |
441 startline)))) | |
442 (lines (- endline startline)) | |
443 (otherlines (cond | |
444 ((eq op ?d) nil) | |
445 ((null (match-end 5)) 1) | |
446 (t (- (string-to-number (match-string 5)) | |
447 (string-to-number (match-string 4)) -1)))) | |
448 othertext) | |
449 (forward-line 1) ;Skip header. | |
450 (forward-line lines) ;Skip deleted text. | |
451 (if (eq op ?c) (forward-line 1)) ;Skip separator. | |
452 (setq othertext | |
453 (if (null otherlines) "" | |
454 (let ((pos (point))) | |
455 (dotimes (i otherlines) (delete-char 2) (forward-line 1)) | |
456 (buffer-substring pos (point))))) | |
457 (with-current-buffer textbuf | |
458 (forward-line (- startline line)) | |
459 (insert "<<<<<<< " name1 "\n" othertext | |
460 (if name2 (concat "||||||| " name2)) | |
461 "=======\n") | |
462 (forward-line lines) | |
463 (insert ">>>>>>> " name3 "\n") | |
464 (setq line endline)))))))) | |
465 | |
410 (defun smerge-resolve (&optional safe) | 466 (defun smerge-resolve (&optional safe) |
411 "Resolve the conflict at point intelligently. | 467 "Resolve the conflict at point intelligently. |
412 This relies on mode-specific knowledge and thus only works in | 468 This relies on mode-specific knowledge and thus only works in |
413 some major modes. Uses `smerge-resolve-function' to do the actual work." | 469 some major modes. Uses `smerge-resolve-function' to do the actual work." |
414 (interactive) | 470 (interactive) |
415 (smerge-match-conflict) | 471 (smerge-match-conflict) |
416 (smerge-remove-props (match-beginning 0) (match-end 0)) | 472 (smerge-remove-props (match-beginning 0) (match-end 0)) |
417 (cond | 473 (let ((md (match-data)) |
418 ;; Trivial diff3 -A non-conflicts. | 474 (m0b (match-beginning 0)) |
419 ((and (eq (match-end 1) (match-end 3)) | 475 (m1b (match-beginning 1)) |
420 (eq (match-beginning 1) (match-beginning 3))) | 476 (m2b (match-beginning 2)) |
421 (smerge-keep-n 3)) | 477 (m3b (match-beginning 3)) |
422 ;; Mode-specific conflict resolution. | 478 (m0e (match-end 0)) |
423 ((condition-case nil | 479 (m1e (match-end 1)) |
424 (atomic-change-group | 480 (m2e (match-end 2)) |
425 (if safe | 481 (m3e (match-end 3)) |
426 (funcall smerge-resolve-function safe) | 482 (buf (generate-new-buffer " *smerge*")) |
427 (funcall smerge-resolve-function)) | 483 m b o) |
428 t) | 484 (unwind-protect |
429 (error nil)) | 485 (progn |
430 ;; Nothing to do: the resolution function has done it already. | 486 (cond |
431 nil) | 487 ;; Trivial diff3 -A non-conflicts. |
432 ;; FIXME: Add "if [ diff -b MINE OTHER ]; then select OTHER; fi" | 488 ((and (eq (match-end 1) (match-end 3)) |
433 ((and (match-end 2) | 489 (eq (match-beginning 1) (match-beginning 3))) |
434 ;; FIXME: Add "diff -b BASE MINE | patch OTHER". | 490 (smerge-keep-n 3)) |
435 ;; FIXME: Add "diff -b BASE OTHER | patch MINE". | 491 ;; Mode-specific conflict resolution. |
436 nil) | 492 ((condition-case nil |
437 ) | 493 (atomic-change-group |
438 ((and (not (match-end 2)) | 494 (if safe |
439 ;; FIXME: Add "diff -b"-based refinement. | 495 (funcall smerge-resolve-function safe) |
440 nil) | 496 (funcall smerge-resolve-function)) |
441 ) | 497 t) |
442 (t | 498 (error nil)) |
443 (error "Don't know how to resolve"))) | 499 ;; Nothing to do: the resolution function has done it already. |
500 nil) | |
501 ;; "Mere whitespace" conflicts. | |
502 ((or (and (eq m1e m3e) (eq m1b m3b)) ;Non-conflict. | |
503 (progn | |
504 (setq m (make-temp-file "smm")) | |
505 (write-region m1b m1e m nil 'silent) | |
506 (setq o (make-temp-file "smo")) | |
507 (write-region m3b m3e o nil 'silent) | |
508 ;; Same patch applied on both sides, with whitespace changes. | |
509 (zerop (call-process diff-command nil nil nil "-b" m o))) | |
510 (when m2e | |
511 (setq b (make-temp-file "smb")) | |
512 (write-region m2b m2e b nil 'silent) | |
513 ;; Only minor whitespace changes made locally. | |
514 (zerop (call-process diff-command nil buf nil "-bc" b m)))) | |
515 (set-match-data md) | |
516 (smerge-keep-n 3)) | |
517 ;; Refine a 2-way conflict using "diff -b". | |
518 ;; In case of a 3-way conflict with an empty base | |
519 ;; (i.e. 2 conflicting additions), we do the same, presuming | |
520 ;; that the 2 additions should be somehow merged rather | |
521 ;; than concatenated. | |
522 ((not (or (and m2b (not (eq m2b m2e))) | |
523 (eq m1b m1e) (eq m3b m3e) | |
524 (let ((lines (count-lines m3b m3e))) | |
525 (call-process diff-command nil buf nil "-b" o m) | |
526 (with-current-buffer buf | |
527 (goto-char (point-min)) | |
528 ;; Make sure there's some refinement. | |
529 (looking-at | |
530 (concat "1," (number-to-string lines) "c")))))) | |
531 (smerge-apply-resolution-patch buf m0b m0e m3b m3e m2b)) | |
532 ;; Try "diff -b BASE MINE | patch OTHER". | |
533 ((when (and (not safe) m2e b | |
534 ;; If the BASE is empty, this would just concatenate | |
535 ;; the two, which is rarely right. | |
536 (not (eq m2b m2e))) | |
537 (with-current-buffer buf | |
538 (zerop (call-process-region | |
539 (point-min) (point-max) "patch" t nil nil | |
540 "-r" "/dev/null" "--no-backup-if-mismatch" | |
541 "-fl" o)))) | |
542 (save-restriction | |
543 (narrow-to-region m0b m0e) | |
544 (smerge-remove-props m0b m0e) | |
545 (insert-file-contents o nil nil nil t))) | |
546 ;; Try "diff -b BASE OTHER | patch MINE". | |
547 ((when (and (not safe) m2e b | |
548 ;; If the BASE is empty, this would just concatenate | |
549 ;; the two, which is rarely right. | |
550 (not (eq m2b m2e))) | |
551 (write-region m3b m3e o nil 'silent) | |
552 (call-process diff-command nil buf nil "-bc" b o) | |
553 (with-current-buffer buf | |
554 (zerop (call-process-region | |
555 (point-min) (point-max) "patch" t nil nil | |
556 "-r" "/dev/null" "--no-backup-if-mismatch" | |
557 "-fl" m)))) | |
558 (save-restriction | |
559 (narrow-to-region m0b m0e) | |
560 (smerge-remove-props m0b m0e) | |
561 (insert-file-contents m nil nil nil t))) | |
562 (t | |
563 (error "Don't know how to resolve")))) | |
564 (if (buffer-name buf) (kill-buffer buf)) | |
565 (if m (delete-file m)) | |
566 (if b (delete-file b)) | |
567 (if o (delete-file o)))) | |
444 (smerge-auto-leave)) | 568 (smerge-auto-leave)) |
445 | 569 |
446 (defun smerge-resolve-all () | 570 (defun smerge-resolve-all () |
447 "Perform automatic resolution on all conflicts." | 571 "Perform automatic resolution on all conflicts." |
448 (interactive) | 572 (interactive) |