Function: diff-add-log-current-defuns

diff-add-log-current-defuns is a byte-compiled function defined in diff-mode.el.gz.

Signature

(diff-add-log-current-defuns)

Documentation

Return an alist of defun names for the current diff.

The elements of the alist are of the form (FILE . (DEFUN...)), where DEFUN... is a list of function names found in FILE. If diff-add-log-use-relative-names is non-nil, file names in the alist are relative to the root directory of the VC repository.

Source Code

;; Defined in /usr/src/emacs/lisp/vc/diff-mode.el.gz
(defun diff-add-log-current-defuns ()
  "Return an alist of defun names for the current diff.
The elements of the alist are of the form (FILE . (DEFUN...)),
where DEFUN... is a list of function names found in FILE.  If
`diff-add-log-use-relative-names' is non-nil, file names in the alist
are relative to the root directory of the VC repository."
  (save-excursion
    (goto-char (point-min))
    (let* ((defuns nil)
           (hunk-end nil)
           (hunk-mismatch-files nil)
           (make-defun-context-follower
            (lambda (goline)
              (let ((eodefun nil)
                    (defname nil))
                (list
                 (lambda () ;; Check for end of current defun.
                   (when (and eodefun
                              (funcall goline)
                              (>= (point) eodefun))
                     (setq defname nil)
                     (setq eodefun nil)))
                 (lambda (&optional get-current) ;; Check for new defun.
                   (if get-current
                       defname
                     (when-let* ((def (and (not eodefun)
                                           (funcall goline)
                                           (add-log-current-defun)))
                                 (eof (save-excursion
                                        (condition-case ()
                                            (progn (end-of-defun) (point))
                                          (scan-error hunk-end)))))
                       (setq eodefun eof)
                       (setq defname def)))))))))
      (while
          ;; Might need to skip over file headers between diff
          ;; hunks (e.g., "diff --git ..." etc).
          (re-search-forward diff-hunk-header-re nil t)
        (setq hunk-end (save-excursion (diff-end-of-hunk)))
        (pcase-let* ((filename (substring-no-properties
                                (if diff-add-log-use-relative-names
                                    (file-relative-name
                                     (diff-find-file-name)
                                     (vc-root-dir))
                                  (diff-find-file-name))))
                     (=lines 0)
                     (+lines 0)
                     (-lines 0)
                     (`(,buf ,line-offset (,beg . ,_end)
                             (,old-text . ,_old-offset)
                             (,new-text . ,_new-offset)
                             ,applied)
                      ;; Try to use the vc integration of
                      ;; `diff-find-source-location', unless it
                      ;; would look for non-existent files like
                      ;; /dev/null.
                      (diff-find-source-location
                       (not (equal null-device
                                   (car (diff-hunk-file-names t))))))
                     (other-buf nil)
                     (goto-otherbuf
                      ;; If APPLIED, we have NEW-TEXT in BUF, so we
                      ;; need to a buffer with OLD-TEXT to follow
                      ;; -lines.
                      (lambda ()
                        (if other-buf (set-buffer other-buf)
                          (set-buffer (generate-new-buffer " *diff-other-text*"))
                          (insert (if applied old-text new-text))
                          (let ((delay-mode-hooks t))
                            (funcall (buffer-local-value 'major-mode buf)))
                          (setq other-buf (current-buffer)))
                        (goto-char (point-min))
                        (forward-line (+ =lines -1
                                         (if applied -lines +lines)))))
                     (gotobuf (lambda ()
                                (set-buffer buf)
                                (goto-char beg)
                                (forward-line (+ =lines -1
                                                 (if applied +lines -lines)))))
                     (`(,=ck-eodefun ,=ck-defun)
                      (funcall make-defun-context-follower gotobuf))
                     (`(,-ck-eodefun ,-ck-defun)
                      (funcall make-defun-context-follower
                               (if applied goto-otherbuf gotobuf)))
                     (`(,+ck-eodefun ,+ck-defun)
                      (funcall make-defun-context-follower
                               (if applied gotobuf goto-otherbuf))))
          (unless (eql line-offset 0)
            (cl-pushnew filename hunk-mismatch-files :test #'equal))
          ;; Some modes always return nil for `add-log-current-defun',
          ;; make sure at least the filename is included.
          (unless (assoc filename defuns)
            (push (cons filename nil) defuns))
          (unwind-protect
              (while (progn (forward-line)
                            (< (point) hunk-end))
                (let ((patch-char (char-after)))
                  (pcase patch-char
                    (?+ (incf +lines))
                    (?- (incf -lines))
                    (?\s (incf =lines)))
                  (save-current-buffer
                    (funcall =ck-eodefun)
                    (funcall +ck-eodefun)
                    (funcall -ck-eodefun)
                    (when-let* ((def (cond
                                      ((eq patch-char ?\s)
                                       ;; Just updating context defun.
                                       (ignore (funcall =ck-defun)))
                                      ;; + or - in existing defun.
                                      ((funcall =ck-defun t))
                                      ;; Check added or removed defun.
                                      (t (funcall (if (eq ?+ patch-char)
                                                      +ck-defun -ck-defun))))))
                      (cl-pushnew def (alist-get filename defuns
                                                 nil nil #'equal)
                                  :test #'equal)))))
            (when (buffer-live-p other-buf)
              (kill-buffer other-buf)))))
      (when hunk-mismatch-files
        (message "Diff didn't match for %s."
                 (mapconcat #'identity hunk-mismatch-files ", ")))
      (dolist (file-defuns defuns)
        (cl-callf nreverse (cdr file-defuns)))
      (nreverse defuns))))