Function: diff--refine-hunk

diff--refine-hunk is a byte-compiled function defined in diff-mode.el.gz.

Signature

(diff--refine-hunk START END &optional SKIP-IF-LARGE)

Source Code

;; Defined in /usr/src/emacs/lisp/vc/diff-mode.el.gz
(defun diff--refine-hunk (start end &optional skip-if-large)
  (require 'smerge-mode)
  (goto-char start)
  (let* ((style (diff-hunk-style))      ;Skips the hunk header as well.
         (beg (point))
         (props-c '((diff-mode . fine) (face . diff-refine-changed)))
         (props-r '((diff-mode . fine) (face . diff-refine-removed)))
         (props-a '((diff-mode . fine) (face . diff-refine-added))))

    (remove-overlays beg end 'diff-mode 'fine)

    (goto-char beg)
    (pcase style
      ((guard (and skip-if-large
                   ;; FIXME: Maybe instead of testing the hunk size, we
                   ;; should test the size of each individual "delete+insert"
                   ;; pairs, since a big hunk with many small del+ins pairs
                   ;; should not suffer from the usual pathological
                   ;; complexity problems.
                   ;; Or maybe even push the test down into
                   ;; `smerge-refine-regions' where `smerge-mode' could
                   ;; also use it?
                   (> (- end beg) diff-refine-threshold)))
       nil)
      ('unified
       (while (re-search-forward "^[-+]" end t)
         (let ((beg-del (progn (beginning-of-line) (point)))
               beg-add end-add)
           (cond
            ((eq (char-after) ?+)
             (diff--forward-while-leading-char ?+ end)
             (when diff-refine-nonmodified
               (diff--refine-propertize beg-del (point) 'diff-refine-added)))
            ((and (diff--forward-while-leading-char ?- end)
                  ;; Allow for "\ No newline at end of file".
                  (progn (diff--forward-while-leading-char ?\\ end)
                         (setq beg-add (point)))
                  (diff--forward-while-leading-char ?+ end)
                  (progn (diff--forward-while-leading-char ?\\ end)
                         (setq end-add (point))))
             (smerge-refine-regions beg-del beg-add beg-add end-add
                                    nil #'diff-refine-preproc props-r props-a))
            (t ;; If we're here, it's because
             ;; (diff--forward-while-leading-char ?+ end) failed.
             (when diff-refine-nonmodified
              (diff--refine-propertize beg-del (point)
                                       'diff-refine-removed)))))))
      ('context
       (let* ((middle (save-excursion (re-search-forward "^---" end t)))
              (other middle))
         (when middle
           (while (re-search-forward "^\\(?:!.*\n\\)+" middle t)
             (smerge-refine-regions (match-beginning 0) (match-end 0)
                                    (save-excursion
                                      (goto-char other)
                                      (re-search-forward "^\\(?:!.*\n\\)+" end)
                                      (setq other (match-end 0))
                                      (match-beginning 0))
                                    other
                                    (if diff-use-changed-face props-c)
                                    #'diff-refine-preproc
                                    (unless diff-use-changed-face props-r)
                                    (unless diff-use-changed-face props-a)))
           (when diff-refine-nonmodified
             (goto-char beg)
             (while (re-search-forward "^\\(?:-.*\n\\)+" middle t)
               (diff--refine-propertize (match-beginning 0)
                                        (match-end 0)
                                        'diff-refine-removed))
             (goto-char middle)
             (while (re-search-forward "^\\(?:\\+.*\n\\)+" end t)
               (diff--refine-propertize (match-beginning 0)
                                        (match-end 0)
                                        'diff-refine-added))))))
      (_ ;; Normal diffs.
       (let ((beg1 (1+ (point))))
         (cond
          ((re-search-forward "^---.*\n" end t)
           ;; It's a combined add&remove, so there's something to do.
           (smerge-refine-regions beg1 (match-beginning 0)
                                  (match-end 0) end
                                  nil #'diff-refine-preproc props-r props-a))
          (diff-refine-nonmodified
           (diff--refine-propertize
            beg1 end
            (if (eq (char-after beg1) ?<)
                'diff-refine-removed 'diff-refine-added)))))))))