Function: vc-diff-internal

vc-diff-internal is a byte-compiled function defined in vc.el.gz.

Signature

(vc-diff-internal ASYNC VC-FILESET REV1 REV2 &optional VERBOSE BUFFER)

Documentation

Report diffs between revisions REV1 and REV2 of a fileset in VC-FILESET.

ASYNC non-nil means run the backend's commands asynchronously if possible. VC-FILESET should have the format described in vc-deduce-fileset. Output goes to the buffer BUFFER, which defaults to *vc-diff*. BUFFER, if non-nil, should be a buffer or a buffer name. Return t if the buffer had changes, nil otherwise.

Source Code

;; Defined in /usr/src/emacs/lisp/vc/vc.el.gz
(defun vc-diff-internal (async vc-fileset rev1 rev2 &optional verbose buffer)
  "Report diffs between revisions REV1 and REV2 of a fileset in VC-FILESET.
ASYNC non-nil means run the backend's commands asynchronously if possible.
VC-FILESET should have the format described in `vc-deduce-fileset'.
Output goes to the buffer BUFFER, which defaults to *vc-diff*.
BUFFER, if non-nil, should be a buffer or a buffer name.
Return t if the buffer had changes, nil otherwise."
  (unless buffer
    (setq buffer "*vc-diff*"))
  (let* ((files (cadr vc-fileset))
	 (messages (cons (format "Finding changes in %s..."
                                 (vc-delistify files))
                         (format "No changes between %s and %s"
                                 (or rev1 "working revision")
                                 (or rev2 "workfile"))))
	 ;; Set coding system based on the first file.  It's a kluge,
	 ;; but the only way to set it for each file included would
	 ;; be to call the back end separately for each file.
	 (coding-system-for-read
          ;; Force the EOL conversion to be -unix, in case the files
          ;; to be compared have DOS EOLs.  In that case, EOL
          ;; conversion will produce a patch file that will either
          ;; fail to apply, or will change the EOL format of some of
          ;; the lines in the patched file.
          (coding-system-change-eol-conversion
	   (if files (vc-coding-system-for-diff (car files)) 'undecided)
           'unix))
         (orig-diff-buffer-clone
          (if revert-buffer-in-progress-p
              (clone-buffer
               (generate-new-buffer-name " *vc-diff-clone*") nil))))
    ;; On MS-Windows and MS-DOS, Diff is likely to produce DOS-style
    ;; EOLs, which will look ugly if (car files) happens to have Unix
    ;; EOLs.  But for Git, we must force Unix EOLs in the diffs, since
    ;; Git always produces Unix EOLs in the parts that didn't come
    ;; from the file, and wants to see any CR characters when applying
    ;; patches.
    (if (and (memq system-type '(windows-nt ms-dos))
             (not (eq (car vc-fileset) 'Git)))
	(setq coding-system-for-read
	      (coding-system-change-eol-conversion coding-system-for-read
						   'dos)))
    (vc-setup-buffer buffer)
    (message "%s" (car messages))
    ;; Many backends don't handle well the case of a file that has been
    ;; added but not yet committed to the repo (notably CVS and Subversion).
    ;; Do that work here so the backends don't have to futz with it.  --ESR
    ;;
    ;; Actually most backends (including CVS) have options to control the
    ;; behavior since which one is better depends on the user and on the
    ;; situation).  Worse yet: this code does not handle the case where
    ;; `file' is a directory which contains added files.
    ;; I made it conditional on vc-diff-added-files but it should probably
    ;; just be removed (or copied/moved to specific backends).  --Stef.
    (when vc-diff-added-files
      (let ((filtered '())
	    process-file-side-effects)
        (dolist (file files)
          (if (or (file-directory-p file)
                  (not (string= (vc-working-revision file) "0")))
              (push file filtered)
            ;; This file is added but not yet committed;
            ;; there is no repository version to diff against.
            (if (or rev1 rev2)
                (error "No revisions of %s exist" file)
              ;; We regard this as "changed".
              ;; Diff it against /dev/null.
              (apply #'vc-do-command buffer
                     (if async 'async 1) "diff" file
                     (append (vc-switches nil 'diff) `(,(null-device)))))))
        (setq files (nreverse filtered))))
    (vc-call-backend (car vc-fileset) 'diff files rev1 rev2 buffer async)
    (set-buffer buffer)
    ;; Make the *vc-diff* buffer read only, the diff-mode key
    ;; bindings are nicer for read only buffers. pcl-cvs does the
    ;; same thing.
    (setq buffer-read-only t)
    (diff-mode)
    (setq-local diff-vc-backend (car vc-fileset))
    (setq-local diff-vc-revisions (list rev1 rev2))
    (setq-local revert-buffer-function
                (lambda (_ignore-auto _noconfirm)
                  (vc-diff-internal async vc-fileset rev1 rev2 verbose)))
    (if (and (zerop (buffer-size))
             (not (get-buffer-process (current-buffer))))
        ;; Treat this case specially so as not to pop the buffer.
        (progn
          (message "%s" (cdr messages))
          nil)
      ;; Display the buffer, but at the end because it can change point.
      (pop-to-buffer (current-buffer))
      ;; The diff process may finish early, so call `vc-diff-finish'
      ;; after `pop-to-buffer'; the former assumes the diff buffer is
      ;; shown in some window.
      (let ((buf (current-buffer)))
        (vc-run-delayed (vc-diff-finish buf (when verbose messages)
                                        orig-diff-buffer-clone)))
      ;; In the async case, we return t even if there are no differences
      ;; because we don't know that yet.
      t)))