3737
3838(defvar diff-hl-dired-process-buffer nil )
3939
40+ (defvar diff-hl-dired--pending nil
41+ " Non-nil if a `diff-hl-dired-update' is pending due to concurrent VC process." )
42+
4043(defgroup diff-hl-dired nil
4144 " VC diff highlighting on the side of a Dired window."
4245 :group 'diff-hl )
5962
6063(defface diff-hl-dired-ignored
6164 '((default :inherit dired-ignored ))
62- " Face used to highlight unregistered files." )
65+ " Face used to highlight ignored files." )
6366
6467(defcustom diff-hl-dired-extra-indicators t
6568 " Non-nil to indicate ignored files."
@@ -86,6 +89,7 @@ status indicators."
8689 (progn
8790 (diff-hl-maybe-define-bitmaps)
8891 (set (make-local-variable 'diff-hl-dired-process-buffer ) nil )
92+ (set (make-local-variable 'diff-hl-dired--pending ) nil )
8993 (add-hook 'dired-after-readin-hook 'diff-hl-dired-update nil t ))
9094 (remove-hook 'dired-after-readin-hook 'diff-hl-dired-update t )
9195 (diff-hl-dired-clear)))
@@ -95,66 +99,90 @@ status indicators."
9599 (let ((backend (ignore-errors (vc-responsible-backend default-directory)))
96100 (def-dir default-directory)
97101 (buffer (current-buffer ))
102+ (state-to-type '( edited change
103+ added insert
104+ removed delete
105+ unregistered unknown
106+ ignored ignored))
98107 dirs-alist files-alist)
99108 (when (and backend (not (memq backend diff-hl-dired-ignored-backends)))
100- (diff-hl-dired-clear)
101- (if (buffer-live-p diff-hl-dired-process-buffer)
102- (let ((proc (get-buffer-process diff-hl-dired-process-buffer)))
103- (when proc (kill-process proc)))
104- (setq diff-hl-dired-process-buffer
105- (generate-new-buffer " *diff-hl-dired* tmp status" )))
106- (with-current-buffer diff-hl-dired-process-buffer
107- (setq default-directory (expand-file-name def-dir))
108- (erase-buffer )
109- (diff-hl-dired-status-files
110- backend def-dir
111- (when diff-hl-dired-extra-indicators
112- (cl-loop for file in (directory-files def-dir)
113- unless (member file '(" ." " .." " .hg" ))
114- collect file))
115- (lambda (entries &optional more-to-come )
116- (when (buffer-live-p buffer)
117- (with-current-buffer buffer
118- (dolist (entry entries)
119- (cl-destructuring-bind (file state &rest r) entry
120- ; ; Work around http://debbugs.gnu.org/18605
121- (setq file (replace-regexp-in-string " \\ ` " " " file))
122- (let ((type (plist-get
123- '( edited change added insert removed delete
124- unregistered unknown ignored ignored)
125- state)))
126- (if (string-match " \\ `\\ ([^/]+\\ )/" file)
127- (let* ((dir (match-string 1 file))
128- (value (cdr (assoc dir dirs-alist))))
129- (unless (eq value type)
130- (cond
131- ((eq state 'up-to-date ))
132- ((null value)
133- (push (cons dir type) dirs-alist))
134- ((not (eq type 'ignored ))
135- (setcdr (assoc dir dirs-alist) 'change )))))
136- (push (cons file type) files-alist)))))
137- (unless more-to-come
138- (diff-hl-dired-highlight-items
139- (append dirs-alist files-alist))))
140- (unless more-to-come
141- (kill-buffer diff-hl-dired-process-buffer))))
142- )))))
109+ ; ; queue update if VC process running
110+ ; ; pending flag debounces: N calls -> 1 retry
111+ ; ; e.g., open N subtrees while VC runs -> 1 retry after completion
112+ (if (and (buffer-live-p diff-hl-dired-process-buffer)
113+ (get-buffer-process diff-hl-dired-process-buffer)
114+ (process-live-p (get-buffer-process diff-hl-dired-process-buffer)))
115+ (setq diff-hl-dired--pending t ) ; ; queued, early return
116+ (setq diff-hl-dired--pending nil )
117+ (unless (buffer-live-p diff-hl-dired-process-buffer)
118+ (setq diff-hl-dired-process-buffer
119+ (generate-new-buffer " *diff-hl-dired* tmp status" )))
120+ (with-current-buffer diff-hl-dired-process-buffer
121+ (setq default-directory (expand-file-name def-dir))
122+ (erase-buffer )
123+ (let ((files
124+ (when diff-hl-dired-extra-indicators
125+ (cl-loop for file in (directory-files def-dir)
126+ unless (member file '(" ." " .." " .hg" ))
127+ collect file)))
128+ (update-fn
129+ (lambda (entries &optional more-to-come )
130+ (when (buffer-live-p buffer)
131+ (with-current-buffer buffer
132+ (dolist (entry entries)
133+ (cl-destructuring-bind (file state &rest r) entry
134+ ; ; Work around http://debbugs.gnu.org/18605
135+ (setq file (replace-regexp-in-string " \\ ` " " " file))
136+ (let ((type (plist-get state-to-type state))
137+ (dirs (cl-loop with pos = 0
138+ while (string-match " /" file pos)
139+ do (setq pos (match-end 0 ))
140+ collect (substring file 0 (1- pos)))))
141+ (dolist (dir dirs)
142+ (let ((value (cdr (assoc dir dirs-alist))))
143+ (cond
144+ ((eq value type)) ; ; skip
145+ ((eq state 'up-to-date )) ; ; skip
146+ ((null value)
147+ (push (cons dir type) dirs-alist))
148+ ((not (eq type 'ignored ))
149+ (setcdr (assoc dir dirs-alist) 'change )))))
150+ (push (cons file type) files-alist)
151+ )))
152+ (unless more-to-come
153+ (diff-hl-dired-highlight-items
154+ (append dirs-alist files-alist))
155+ (when diff-hl-dired--pending
156+ (run-at-time 0 nil
157+ (lambda ()
158+ (when (buffer-live-p buffer)
159+ (with-current-buffer buffer
160+ (setq diff-hl-dired--pending nil )
161+ (diff-hl-dired-update))))))))
162+ (unless more-to-come
163+ (kill-buffer diff-hl-dired-process-buffer))))))
164+ (diff-hl-dired-status-files backend def-dir files update-fn)))
165+ ))))
143166
144167(defun diff-hl-dired-status-files (backend dir files update-function )
145168 " Using version control BACKEND, return list of (FILE STATE EXTRA) entries
146169for DIR containing FILES. Call UPDATE-FUNCTION as entries are added."
147- (vc-call-backend backend 'dir-status-files dir files update-function))
170+ (vc-call-backend backend 'dir-status-files
171+ dir files update-function))
148172
149173(defun diff-hl-dired-highlight-items (alist )
150174 " Highlight ALIST containing (FILE . TYPE) elements."
175+ ; ; clear overlays right before drawing to avoid flicker
176+ (diff-hl-dired-clear)
151177 (dolist (pair alist)
152178 (let ((file (car pair))
153179 (type (cdr pair)))
154180 (save-excursion
155181 (goto-char (point-min ))
156- (when (and type (dired-goto-file-1
157- file (expand-file-name file) nil ))
182+ (when (and type
183+ (dired-goto-file-1
184+ (file-name-nondirectory file) ; ; basename
185+ (expand-file-name file) nil ))
158186 (let* ((diff-hl-fringe-bmp-function diff-hl-dired-fringe-bmp-function)
159187 (diff-hl-fringe-face-function 'diff-hl-dired-face-from-type )
160188 (o (diff-hl-add-highlighting type 'single )))
0 commit comments