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))