Function: vc-dir-update
vc-dir-update is a byte-compiled function defined in vc-dir.el.gz.
Signature
(vc-dir-update ENTRIES BUFFER &optional NOINSERT)
Documentation
Update BUFFER's VC-Dir ewoc from ENTRIES.
This has the effect of adding ENTRIES to the VC-Dir buffer BUFFER. If optional argument NOINSERT is non-nil, update ewoc nodes, but don't add elements of ENTRIES to the buffer that aren't already in the ewoc. Also update some VC file properties from ENTRIES.
Source Code
;; Defined in /usr/src/emacs/lisp/vc/vc-dir.el.gz
(defun vc-dir-update (entries buffer &optional noinsert)
"Update BUFFER's VC-Dir ewoc from ENTRIES.
This has the effect of adding ENTRIES to the VC-Dir buffer BUFFER.
If optional argument NOINSERT is non-nil, update ewoc nodes, but don't
add elements of ENTRIES to the buffer that aren't already in the ewoc.
Also update some VC file properties from ENTRIES."
(with-current-buffer buffer
;; Insert the entries sorted by name into the ewoc.
;; We assume the ewoc is sorted too, which should be the
;; case if we always add entries with vc-dir-update.
(setq entries
(let ((entry-dirs
(mapcar (lambda (entry)
(cons (file-name-directory
(directory-file-name (expand-file-name (car entry))))
entry))
entries)))
;; Sort: first files and then subdirectories.
(mapcar #'cdr
(sort entry-dirs
(lambda (pair1 pair2)
(let ((dir1 (car pair1))
(dir2 (car pair2)))
(cond
((string< dir1 dir2) t)
((not (string= dir1 dir2)) nil)
((string< (cadr pair1) (cadr pair2))))))))))
;; Insert directory entries in the right places.
(let ((entry (car entries))
(node (ewoc-nth vc-ewoc 0))
(to-remove nil)
(dotname (file-relative-name default-directory)))
;; Insert . if it is not present.
(unless node
(ewoc-enter-last
vc-ewoc (vc-dir-create-fileinfo
dotname nil nil nil default-directory))
(setq node (ewoc-nth vc-ewoc 0)))
(while (and entry node)
(let* ((entryfile (car entry))
(entrydir (file-name-directory (directory-file-name
(expand-file-name entryfile))))
(nodedir (vc-dir-node-directory node)))
(cond
;; First try to find the directory.
((string-lessp nodedir entrydir)
(setq node (ewoc-next vc-ewoc node)))
((string-equal nodedir entrydir)
;; Found the directory, find the place for the file name.
(let ((nodefile (vc-dir-fileinfo->name (ewoc-data node))))
(cond
((string= nodefile dotname)
(setq node (ewoc-next vc-ewoc node)))
((string-lessp nodefile entryfile)
(setq node (ewoc-next vc-ewoc node)))
((string-equal nodefile entryfile)
(let ((state (nth 1 entry)))
(if (or (null state)
(and vc-dir-auto-hide-up-to-date
(not (eq vc-dir-auto-hide-up-to-date 'revert))
(memq state vc-dir--up-to-date-states)))
(push node to-remove)
(setf (vc-dir-fileinfo->state (ewoc-data node)) state)
(setf (vc-dir-fileinfo->display-state (ewoc-data node))
(vc--file-getinheprop nodefile 'display-state))
(setf (vc-dir-fileinfo->extra (ewoc-data node))
(nth 2 entry))
(setf (vc-dir-fileinfo->needs-update (ewoc-data node)) nil)
(ewoc-invalidate vc-ewoc node))
(setq entries (cdr entries))
(setq entry (car entries))
(setq node (ewoc-next vc-ewoc node))))
(t
(unless noinsert
(ewoc-enter-before vc-ewoc node
(apply #'vc-dir-create-fileinfo entry)))
(setq entries (cdr entries))
(setq entry (car entries))))))
(t
(unless noinsert
;; We might need to insert a directory node if the
;; previous node was in a different directory.
(let* ((rd (file-relative-name entrydir))
(prev-node (ewoc-prev vc-ewoc node))
(prev-dir (if prev-node
(vc-dir-node-directory prev-node))))
(unless (string-equal entrydir prev-dir)
(ewoc-enter-before
vc-ewoc node (vc-dir-create-fileinfo rd nil nil nil entrydir))))
;; Now insert the node itself.
(ewoc-enter-before vc-ewoc node
(apply #'vc-dir-create-fileinfo entry)))
(setq entries (cdr entries) entry (car entries))))))
;; We're past the last node, all remaining entries go to the end.
(unless (or node noinsert)
(let ((lastdir (vc-dir-node-directory (ewoc-nth vc-ewoc -1))))
(dolist (entry entries)
(let ((entrydir (file-name-directory
(directory-file-name
(expand-file-name (car entry))))))
;; Insert a directory node if needed.
(unless (string-equal lastdir entrydir)
(setq lastdir entrydir)
(let ((rd (file-relative-name entrydir)))
(ewoc-enter-last
vc-ewoc (vc-dir-create-fileinfo rd nil nil nil entrydir))))
;; Now insert the node itself.
(ewoc-enter-last vc-ewoc
(apply #'vc-dir-create-fileinfo entry))))))
(when to-remove
(let ((inhibit-read-only t)
(crt (ewoc-nth vc-ewoc -1))
(first (ewoc-nth vc-ewoc 0)))
(while (not (eq crt first))
(let ((prev (ewoc-prev vc-ewoc crt)))
(cond
;; Remove the entries we queued up for removal.
((eq crt (car to-remove))
(ewoc-delete vc-ewoc (pop to-remove)))
;; Remove directories which (now) have no child files.
((and (vc-dir-fileinfo->directory (ewoc-data crt))
(let ((next (ewoc-next vc-ewoc crt)))
(or (null next)
(vc-dir-fileinfo->directory (ewoc-data next)))))
(ewoc-delete vc-ewoc crt)))
(setq crt prev))))))
;; Update VC file properties.
(pcase-dolist (`(,file ,state ,_extra) entries)
(vc-file-setprop file 'vc-backend
(if (eq state 'unregistered) 'none vc-dir-backend)))))