Function: diff-syntax-fontify-hunk

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

Signature

(diff-syntax-fontify-hunk BEG END OLD)

Documentation

Highlight source language syntax in diff hunk between BEG and END.

When OLD is non-nil, highlight the hunk from the old source.

Source Code

;; Defined in /usr/src/emacs/lisp/vc/diff-mode.el.gz
(defun diff-syntax-fontify-hunk (beg end old)
  "Highlight source language syntax in diff hunk between BEG and END.
When OLD is non-nil, highlight the hunk from the old source."
  (goto-char beg)
  (let* ((hunk (buffer-substring-no-properties beg end))
         ;; Trim a trailing newline to find hunk in diff-syntax-fontify-props
         ;; in diffs that have no newline at end of diff file.
         (text (string-trim-right
                (or (with-demoted-errors (diff-hunk-text hunk (not old) nil))
                    "")))
	 (line (if (looking-at "\\(?:\\*\\{15\\}.*\n\\)?[-@* ]*\\([0-9,]+\\)\\([ acd+]+\\([0-9,]+\\)\\)?")
		   (if old (match-string 1)
		     (if (match-end 3) (match-string 3) (match-string 1)))))
         (line-nb (when line
                    (if (string-match "\\([0-9]+\\),\\([0-9]+\\)" line)
                        (list (string-to-number (match-string 1 line))
                              (string-to-number (match-string 2 line)))
                      (list (string-to-number line) 1)))) ; One-line diffs
         (props
          (or
           (when (and diff-vc-backend
                      (not (eq diff-font-lock-syntax 'hunk-only)))
             (let* ((file (diff-find-file-name old t))
                    (file (and file (expand-file-name file)))
                    (revision (and file (if (not old) (nth 1 diff-vc-revisions)
                                          (or (nth 0 diff-vc-revisions)
                                              (vc-working-revision file))))))
               (when file
                 (if (not revision)
                     ;; Get properties from the current working revision
                     (when (and (not old) (file-readable-p file)
                                (file-regular-p file))
                       (let ((buf (get-file-buffer file)))
                         ;; Try to reuse an existing buffer
                         (if buf
                             (with-current-buffer buf
                               (diff-syntax-fontify-props nil text line-nb))
                           ;; Get properties from the file.
                           (with-current-buffer (get-buffer-create
                                                 " *diff-syntax-file*")
                             (let ((attrs (file-attributes file)))
                               (if (equal diff--syntax-file-attributes attrs)
                                   ;; Same file as last-time, unmodified.
                                   ;; Reuse buffer as-is.
                                   (setq file nil)
                                 (erase-buffer)
                                 (insert-file-contents file)
                                 (setq diff--syntax-file-attributes attrs)))
                             (diff-syntax-fontify-props file text line-nb)))))
                   ;; Get properties from a cached revision
                   (let* ((buffer-name (format " *diff-syntax:%s.~%s~*"
                                               file revision))
                          (buffer (get-buffer buffer-name)))
                     (if buffer
                         ;; Don't re-initialize the buffer (which would throw
                         ;; away the previous fontification work).
                         (setq file nil)
                       (setq buffer (ignore-errors
                                      (vc-find-revision-no-save
                                       file revision
                                       diff-vc-backend
                                       (get-buffer-create buffer-name)))))
                     (when buffer
                       (with-current-buffer buffer
                         (diff-syntax-fontify-props file text line-nb))))))))
           (let ((file (car (diff-hunk-file-names old))))
             (cond
              ((and file diff-default-directory
                    (not (eq diff-font-lock-syntax 'hunk-only))
                    (not diff-vc-backend)
                    (file-readable-p file) (file-regular-p file))
               ;; Try to get full text from the file.
               (with-temp-buffer
                 (insert-file-contents file)
                 (diff-syntax-fontify-props file text line-nb)))
              ;; Otherwise, get properties from the hunk alone
              ((memq diff-font-lock-syntax '(hunk-also hunk-only))
               (with-temp-buffer
                 (insert text)
                 (diff-syntax-fontify-props file text line-nb t))))))))

    ;; Put properties over the hunk text
    (goto-char beg)
    (when (and props (eq (diff-hunk-style) 'unified))
      (while (< (progn (forward-line 1) (point)) end)
        ;; Skip the "\ No newline at end of file" lines as well as the lines
        ;; corresponding to the "other" version.
        (unless (looking-at-p (if old "[+>\\]" "[-<\\]"))
          (if (and old (not (looking-at-p "[-<]")))
              ;; Fontify context lines only from new source,
              ;; don't refontify context lines from old source.
              (pop props)
            (let ((line-props (pop props))
                  (bol (1+ (point))))
              (dolist (prop line-props)
                ;; Ideally, we'd want to use text-properties as in:
                ;;
                ;;     (add-face-text-property
                ;;      (+ bol (nth 0 prop)) (+ bol (nth 1 prop))
                ;;      (nth 2 prop) 'append)
                ;;
                ;; rather than overlays here, but they'd get removed by later
                ;; font-locking.
                ;; This is because we also apply faces outside of the
                ;; beg...end chunk currently font-locked and when font-lock
                ;; later comes to handle the rest of the hunk that we already
                ;; handled we don't (want to) redo it (we work at
                ;; hunk-granularity rather than font-lock's own chunk
                ;; granularity).
                ;; I see two ways to fix this:
                ;; - don't immediately apply the props that fall outside of
                ;;   font-lock's chunk but stash them somewhere (e.g. in another
                ;;   text property) and only later when font-lock comes back
                ;;   move them to `face'.
                ;; - change the code so work at font-lock's chunk granularity
                ;;   (this seems doable without too much extra overhead,
                ;;   contrary to the refine highlighting, which inherently
                ;;   works at a different granularity).
                (let ((ol (make-overlay (+ bol (nth 0 prop))
                                        (+ bol (nth 1 prop))
                                        nil 'front-advance nil)))
                  (overlay-put ol 'diff-mode 'syntax)
                  (overlay-put ol 'evaporate t)
                  (overlay-put ol 'face (nth 2 prop)))))))))))