@@ -479,6 +479,27 @@ and returns the process output as a string."
479479 (setf (git-fileinfo->orig-name info) nil )
480480 (setf (git-fileinfo->needs-refresh info) t ))))
481481
482+ (defun git-set-filenames-state (status files state )
483+ " Set the state of a list of named files."
484+ (when files
485+ (setq files (sort files #'string-lessp ))
486+ (let ((file (pop files ))
487+ (node (ewoc-nth status 0 )))
488+ (while (and file node)
489+ (let ((info (ewoc-data node)))
490+ (cond ((string-lessp (git-fileinfo->name info) file)
491+ (setq node (ewoc-next status node)))
492+ ((string-equal (git-fileinfo->name info) file)
493+ (unless (eq (git-fileinfo->state info) state)
494+ (setf (git-fileinfo->state info) state)
495+ (setf (git-fileinfo->rename-state info) nil )
496+ (setf (git-fileinfo->orig-name info) nil )
497+ (setf (git-fileinfo->needs-refresh info) t ))
498+ (setq file (pop files )))
499+ (t (setq file (pop files )))))))
500+ (unless state ; ; delete files whose state has been set to nil
501+ (ewoc-filter status (lambda (info ) (git-fileinfo->state info))))))
502+
482503(defun git-state-code (code )
483504 " Convert from a string to a added/deleted/modified state."
484505 (case (string-to-char code)
@@ -532,19 +553,36 @@ and returns the process output as a string."
532553 " " (git-escape-file-name (git-fileinfo->name info))
533554 (git-rename-as-string info))))
534555
535- (defun git-insert-fileinfo (status info &optional refresh )
536- " Insert INFO in the status buffer, optionally refreshing an existing one."
537- (let ((node (and refresh
538- (git-find-status-file status (git-fileinfo->name info)))))
539- (setf (git-fileinfo->needs-refresh info) t )
540- (when node ; preserve the marked flag
541- (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node))))
542- (if node (setf (ewoc-data node) info) (ewoc-enter-last status info))))
556+ (defun git-insert-info-list (status infolist )
557+ " Insert a list of file infos in the status buffer, replacing existing ones if any."
558+ (setq infolist (sort infolist
559+ (lambda (info1 info2 )
560+ (string-lessp (git-fileinfo->name info1)
561+ (git-fileinfo->name info2)))))
562+ (let ((info (pop infolist))
563+ (node (ewoc-nth status 0 )))
564+ (while info
565+ (setf (git-fileinfo->needs-refresh info) t )
566+ (cond ((not node)
567+ (ewoc-enter-last status info)
568+ (setq info (pop infolist)))
569+ ((string-lessp (git-fileinfo->name (ewoc-data node))
570+ (git-fileinfo->name info))
571+ (setq node (ewoc-next status node)))
572+ ((string-equal (git-fileinfo->name (ewoc-data node))
573+ (git-fileinfo->name info))
574+ ; ; preserve the marked flag
575+ (setf (git-fileinfo->marked info) (git-fileinfo->marked (ewoc-data node)))
576+ (setf (ewoc-data node) info)
577+ (setq info (pop infolist)))
578+ (t
579+ (ewoc-enter-before status node info)
580+ (setq info (pop infolist)))))))
543581
544582(defun git-run-diff-index (status files )
545583 " Run git-diff-index on FILES and parse the results into STATUS.
546584Return the list of files that haven't been handled."
547- (let ((refresh files ) )
585+ (let (infolist )
548586 (with-temp-buffer
549587 (apply #'git-run-command t nil " diff-index" " -z" " -M" " HEAD" " --" files )
550588 (goto-char (point-min ))
@@ -558,13 +596,14 @@ Return the list of files that haven't been handled."
558596 (new-name (match-string 8 )))
559597 (if new-name ; copy or rename
560598 (if (eq ?C (string-to-char state))
561- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) refresh )
562- (git-insert-fileinfo status (git-create-fileinfo 'deleted name 0 0 'rename new-name) refresh )
563- (git-insert-fileinfo status (git-create-fileinfo 'added new-name old-perm new-perm 'rename name)) refresh )
564- (git-insert-fileinfo status (git-create-fileinfo (git-state-code state) name old-perm new-perm) refresh ))
599+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'copy name) infolist )
600+ (push (git-create-fileinfo 'deleted name 0 0 'rename new-name) infolist )
601+ (push (git-create-fileinfo 'added new-name old-perm new-perm 'rename name) infolist) )
602+ (push (git-create-fileinfo (git-state-code state) name old-perm new-perm) infolist ))
565603 (setq files (delete name files ))
566- (when new-name (setq files (delete new-name files )))))))
567- files )
604+ (when new-name (setq files (delete new-name files ))))))
605+ (git-insert-info-list status infolist)
606+ files ))
568607
569608(defun git-find-status-file (status file )
570609 " Find a given file in the status ewoc and return its node."
@@ -576,16 +615,16 @@ Return the list of files that haven't been handled."
576615(defun git-run-ls-files (status files default-state &rest options )
577616 " Run git-ls-files on FILES and parse the results into STATUS.
578617Return the list of files that haven't been handled."
579- (let ((refresh files ) )
618+ (let (infolist )
580619 (with-temp-buffer
581- (apply #'git-run-command t nil " ls-files" " -z" " -t " (append options (list " --" ) files ))
620+ (apply #'git-run-command t nil " ls-files" " -z" (append options (list " --" ) files ))
582621 (goto-char (point-min ))
583- (while (re-search-forward " \\ ([HMRCK?] \\ ) \\ ([ ^\0 ]*\\ )\0 " nil t 1 )
584- (let ((state (match-string 1 ))
585- (name ( match-string 2 )) )
586- (git-insert-fileinfo status (git-create-fileinfo ( or (git-state-code state) default-state) name) refresh )
587- ( setq files ( delete name files ))))) )
588- files )
622+ (while (re-search-forward " \\ ([^\0 ]*\\ )\0 " nil t 1 )
623+ (let ((name (match-string 1 ) ))
624+ ( push (git-create-fileinfo default-state name) infolist )
625+ (setq files ( delete name files )))) )
626+ (git-insert-info-list status infolist )
627+ files ) )
589628
590629(defun git-run-ls-unmerged (status files )
591630 " Run git-ls-files -u on FILES and parse the results into STATUS."
@@ -594,9 +633,8 @@ Return the list of files that haven't been handled."
594633 (goto-char (point-min ))
595634 (let (unmerged-files)
596635 (while (re-search-forward " [0-7]\\ {6\\ } [0-9a-f]\\ {40\\ } [123]\t \\ ([^\0 ]+\\ )\0 " nil t )
597- (let ((node (git-find-status-file status (match-string 1 ))))
598- (when node (push (ewoc-data node) unmerged-files))))
599- (git-set-files-state unmerged-files 'unmerged ))))
636+ (push (match-string 1 ) unmerged-files))
637+ (git-set-filenames-state status unmerged-files 'unmerged ))))
600638
601639(defun git-get-exclude-files ()
602640 " Get the list of exclude files to pass to git-ls-files."
@@ -622,18 +660,7 @@ Return the list of files that haven't been handled."
622660 (setq remaining-files (apply #'git-run-ls-files status remaining-files 'unknown " -o"
623661 (concat " --exclude-per-directory=" git-per-dir-ignore-file)
624662 (mapcar (lambda (f ) (concat " --exclude-from=" f)) exclude-files)))))
625- ; mark remaining files with the default state (or remove them if nil)
626- (when remaining-files
627- (if default-state
628- (ewoc-map (lambda (info )
629- (when (member (git-fileinfo->name info) remaining-files)
630- (git-set-files-state (list info) default-state))
631- nil )
632- status)
633- (ewoc-filter status
634- (lambda (info files )
635- (not (member (git-fileinfo->name info) files )))
636- remaining-files)))
663+ (git-set-filenames-state status remaining-files default-state)
637664 (git-refresh-files)
638665 (git-refresh-ewoc-hf status)))
639666
0 commit comments