Function: smerge-resolve

smerge-resolve is an interactive and byte-compiled function defined in smerge-mode.el.gz.

Signature

(smerge-resolve &optional SAFE)

Documentation

Resolve the conflict at point intelligently.

This relies on mode-specific knowledge and thus only works in some major modes. Uses smerge-resolve-function to do the actual work.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/vc/smerge-mode.el.gz
(defun smerge-resolve (&optional safe)
  "Resolve the conflict at point intelligently.
This relies on mode-specific knowledge and thus only works in some
major modes.  Uses `smerge-resolve-function' to do the actual work."
  (interactive)
  (smerge-match-conflict)
  ;; FIXME: This ends up removing the refinement-highlighting when no
  ;; resolution is performed.
  (smerge-remove-props (match-beginning 0) (match-end 0))
  (let ((md (match-data))
	(m0b (match-beginning 0))
	(m1b (match-beginning 1))
	(m2b (match-beginning 2))
	(m3b (match-beginning 3))
	(m0e (match-end 0))
	(m1e (match-end 1))
	(m2e (match-end 2))
	(m3e (match-end 3))
	(buf (generate-new-buffer " *smerge*"))
        m b o
        choice)
    (unwind-protect
	(progn
          (cond
           ;; Trivial diff3 -A non-conflicts.
           ((and (eq (match-end 1) (match-end 3))
                 (eq (match-beginning 1) (match-beginning 3)))
            (smerge-keep-n 3))
           ;; Mode-specific conflict resolution.
           ((ignore-errors
              (atomic-change-group
                (if safe
                    (funcall smerge-resolve-function safe)
                  (funcall smerge-resolve-function))
                t))
            ;; Nothing to do: the resolution function has done it already.
            nil)
           ;; Non-conflict.
	   ((and (eq m1e m3e) (eq m1b m3b))
	    (set-match-data md) (smerge-keep-n 3))
           ;; Refine a 2-way conflict using "diff -b".
           ;; In case of a 3-way conflict with an empty base
           ;; (i.e. 2 conflicting additions), we do the same, presuming
           ;; that the 2 additions should be somehow merged rather
           ;; than concatenated.
	   ((let ((lines (count-lines m3b m3e)))
              (setq m (make-temp-file "smm"))
              (write-region m1b m1e m nil 'silent)
              (setq o (make-temp-file "smo"))
              (write-region m3b m3e o nil 'silent)
              (not (or (eq m1b m1e) (eq m3b m3e)
                       (and (not (zerop (call-process diff-command
                                                      nil buf nil "-b" o m)))
                            ;; TODO: We don't know how to do the refinement
                            ;; if there's a non-empty ancestor and m1 and m3
                            ;; aren't just plain equal.
                            m2b (not (eq m2b m2e)))
                       (with-current-buffer buf
                         (goto-char (point-min))
                         ;; Make sure there's some refinement.
                         (looking-at
                          (concat "1," (number-to-string lines) "c"))))))
            (smerge-apply-resolution-patch buf m0b m0e m3b m3e m2b))
	   ;; "Mere whitespace changes" conflicts.
           ((when m2e
              (setq b (make-temp-file "smb"))
              (write-region m2b m2e b nil 'silent)
              (with-current-buffer buf (erase-buffer))
              ;; Only minor whitespace changes made locally.
              ;; BEWARE: pass "-c" 'cause the output is reused in the next test.
              (zerop (call-process diff-command nil buf nil "-bc" b m)))
            (set-match-data md)
	    (smerge-keep-n 3))
	   ;; Try "diff -b BASE UPPER | patch LOWER".
	   ((when (and (not safe) m2e b
                       ;; If the BASE is empty, this would just concatenate
                       ;; the two, which is rarely right.
                       (not (eq m2b m2e)))
              ;; BEWARE: we're using here the patch of the previous test.
	      (with-current-buffer buf
		(zerop (call-process-region
			(point-min) (point-max) "patch" t nil nil
			"-r" null-device "--no-backup-if-mismatch"
			"-fl" o))))
	    (save-restriction
	      (narrow-to-region m0b m0e)
              (smerge-remove-props m0b m0e)
	      (insert-file-contents o nil nil nil t)))
	   ;; Try "diff -b BASE LOWER | patch UPPER".
	   ((when (and (not safe) m2e b
                       ;; If the BASE is empty, this would just concatenate
                       ;; the two, which is rarely right.
                       (not (eq m2b m2e)))
	      (write-region m3b m3e o nil 'silent)
	      (call-process diff-command nil buf nil "-bc" b o)
	      (with-current-buffer buf
		(zerop (call-process-region
			(point-min) (point-max) "patch" t nil nil
			"-r" null-device "--no-backup-if-mismatch"
			"-fl" m))))
	    (save-restriction
	      (narrow-to-region m0b m0e)
              (smerge-remove-props m0b m0e)
	      (insert-file-contents m nil nil nil t)))
           ;; If the conflict is only made of comments, and one of the two
           ;; changes is only rearranging spaces (e.g. reflowing text) while
           ;; the other is a real change, drop the space-rearrangement.
           ((and m2e
                 (comment-only-p m1b m1e)
                 (comment-only-p m2b m2e)
                 (comment-only-p m3b m3e)
                 (let ((t1 (smerge-resolve--extract-comment m1b m1e))
                       (t2 (smerge-resolve--extract-comment m2b m2e))
                       (t3 (smerge-resolve--extract-comment m3b m3e)))
                   (cond
                    ((and (equal t1 t2) (not (equal t2 t3)))
                     (setq choice 3))
                    ((and (not (equal t1 t2)) (equal t2 t3))
                     (setq choice 1)))))
            (set-match-data md)
	    (smerge-keep-n choice))
           ;; Idem, when the conflict is contained within a single comment.
           ((save-excursion
              (and m2e
                   (nth 4 (syntax-ppss m0b))
                   ;; If there's a conflict earlier in the file,
                   ;; syntax-ppss is not reliable.
                   (not (re-search-backward smerge-begin-re nil t))
                   (progn (goto-char (nth 8 (syntax-ppss m0b)))
                          (forward-comment 1)
                          (> (point) m0e))
                   (let ((t1 (smerge-resolve--normalize m1b m1e))
                         (t2 (smerge-resolve--normalize m2b m2e))
                         (t3 (smerge-resolve--normalize m3b m3e)))
                     (cond
                    ((and (equal t1 t2) (not (equal t2 t3)))
                     (setq choice 3))
                    ((and (not (equal t1 t2)) (equal t2 t3))
                     (setq choice 1))))))
            (set-match-data md)
	    (smerge-keep-n choice))
           (t
            (user-error "Don't know how to resolve"))))
      (if (buffer-name buf) (kill-buffer buf))
      (if m (delete-file m))
      (if b (delete-file b))
      (if o (delete-file o))))
  (smerge-auto-leave))