+Returns non-nil if a match is found between point and LIMIT.
+Point is moved to the end of the conflict."
+ (let ((found nil)
+ (pos (point))
+ conflict)
+ ;; First check to see if point is already inside a conflict, using
+ ;; the conflict overlays.
+ (while (and (not found) (setq conflict (smerge-conflict-overlay pos)))
+ ;; Check the overlay's validity and kill it if it's out of date.
+ (condition-case nil
+ (progn
+ (goto-char (overlay-start conflict))
+ (smerge-match-conflict)
+ (goto-char (match-end 0))
+ (if (<= (point) pos)
+ (error "Matching backward!")
+ (setq found t)))
+ (error (smerge-remove-props
+ (overlay-start conflict) (overlay-end conflict))
+ (goto-char pos))))
+ ;; If we're not already inside a conflict, look for the next conflict
+ ;; and add/update its overlay.
+ (while (and (not found) (re-search-forward smerge-begin-re limit t))
+ (condition-case nil
+ (progn
+ (smerge-match-conflict)
+ (goto-char (match-end 0))
+ (let ((conflict (smerge-conflict-overlay (1- (point)))))
+ (if conflict
+ ;; Update its location, just in case it got messed up.
+ (move-overlay conflict (match-beginning 0) (match-end 0))
+ (setq conflict (make-overlay (match-beginning 0) (match-end 0)
+ nil 'front-advance nil))
+ (overlay-put conflict 'evaporate t)
+ (overlay-put conflict 'smerge 'conflict)
+ (let ((props smerge-text-properties))
+ (while props
+ (overlay-put conflict (pop props) (pop props))))))
+ (setq found t))
+ (error nil)))
+ found))
+
+(defun smerge-refine-chopup-region (beg end file)
+ "Chopup the region into small elements, one per line."
+ ;; ediff chops up into words, where the definition of a word is
+ ;; customizable. Instead we here keep only one char per line.
+ ;; The advantages are that there's nothing to configure, that we get very
+ ;; fine results, and that it's trivial to map the line numbers in the
+ ;; output of diff back into buffer positions. The disadvantage is that it
+ ;; can take more time to compute the diff and that the result is sometimes
+ ;; too fine. I'm not too concerned about the slowdown because conflicts
+ ;; are usually significantly smaller than the whole file. As for the
+ ;; problem of too-fine-refinement, I have found it to be unimportant
+ ;; especially when you consider the cases where the fine-grain is just
+ ;; what you want.
+ (let ((buf (current-buffer)))
+ (with-temp-buffer
+ (insert-buffer-substring buf beg end)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (forward-char 1)
+ (unless (eq (char-before) ?\n) (insert ?\n)))
+ (let ((coding-system-for-write 'emacs-mule))
+ (write-region (point-min) (point-max) file nil 'nomessage)))))
+
+(defun smerge-refine-highlight-change (buf beg match-num1 match-num2)
+ (let* ((startline (string-to-number (match-string match-num1)))
+ (ol (make-overlay
+ (+ beg startline -1)
+ (+ beg (if (match-end match-num2)
+ (string-to-number (match-string match-num2))
+ startline))
+ buf
+ 'front-advance nil)))
+ (overlay-put ol 'smerge 'refine)
+ (overlay-put ol 'evaporate t)
+ (overlay-put ol 'face 'smerge-refined-change)))
+
+
+(defun smerge-refine ()
+ "Highlight the parts of the conflict that are different."
+ (interactive)
+ ;; FIXME: make it work with 3-way conflicts.
+ (smerge-match-conflict)
+ (remove-overlays (match-beginning 0) (match-end 0) 'smerge 'refine)
+ (smerge-ensure-match 1)
+ (smerge-ensure-match 3)
+ (let ((buf (current-buffer))
+ ;; Read them before the match-data gets clobbered.
+ (beg1 (match-beginning 1)) (end1 (match-end 1))
+ (beg2 (match-beginning 3)) (end2 (match-end 3))
+ (file1 (make-temp-file "smerge1"))
+ (file2 (make-temp-file "smerge2")))
+
+ ;; Chop up regions into smaller elements and save into files.
+ (smerge-refine-chopup-region beg1 end1 file1)
+ (smerge-refine-chopup-region beg2 end2 file2)
+
+ ;; Call diff on those files.
+ (unwind-protect
+ (with-temp-buffer
+ (let ((coding-system-for-read 'emacs-mule))
+ (call-process diff-command nil t nil file1 file2))
+ ;; Process diff's output.
+ (goto-char (point-min))
+ (while (not (eobp))
+ (if (not (looking-at "\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?\\([acd]\\)\\([0-9]+\\)\\(?:,\\([0-9]+\\)\\)?$"))
+ (error "Unexpected patch hunk header: %s"
+ (buffer-substring (point) (line-end-position)))
+ (let ((op (char-after (match-beginning 3))))
+ (when (memq op '(?d ?c))
+ (smerge-refine-highlight-change buf beg1 1 2))
+ (when (memq op '(?a ?c))
+ (smerge-refine-highlight-change buf beg2 4 5)))
+ (forward-line 1) ;Skip hunk header.
+ (and (re-search-forward "^[0-9]" nil 'move) ;Skip hunk body.
+ (goto-char (match-beginning 0))))))
+ (delete-file file1)
+ (delete-file file2))))