]> git.eshelyaron.com Git - emacs.git/commitdiff
Speed up project-files for Git projects
authorDmitry Gutov <dgutov@yandex.ru>
Thu, 3 Oct 2019 23:03:04 +0000 (02:03 +0300)
committerDmitry Gutov <dgutov@yandex.ru>
Thu, 3 Oct 2019 23:03:23 +0000 (02:03 +0300)
* lisp/progmodes/project.el (project-files): New method.
Implementation for VC projects that uses 'git ls-files' or 'hg
status --all' for listing.  With gratitude to Tassilo Horn who has
done most of the legwork and wrote the first version of the code
(https://lists.gnu.org/archive/html/emacs-devel/2019-10/msg00069.html).
(project--vc-list-files): New function, to be used by the above.
(project--find-regexp-in-files):
Silence warnings about nonexistent files.

lisp/progmodes/project.el

index 4693d07fa86b537bf479b008db38541cb985ae45..2304734bd2487403221d63a9fe875722e6808003 100644 (file)
@@ -277,6 +277,66 @@ backend implementation of `project-external-roots'.")
      (funcall project-vc-external-roots-function)))
    (project-roots project)))
 
+(cl-defmethod project-files ((project (head vc)) &optional dirs)
+  (cl-mapcan
+   (lambda (dir)
+     (let (backend)
+       (if (and (file-equal-p dir (cdr project))
+                (setq backend (vc-responsible-backend dir))
+                (cond
+                 ((eq backend 'Hg))
+                 ((and (eq backend 'Git)
+                       (or
+                        (not project-vc-ignores)
+                        (version<= "1.9" (vc-git--program-version)))))))
+           (project--vc-list-files dir backend project-vc-ignores)
+         (project--files-in-directory
+          dir
+          (project--dir-ignores project dir)))))
+   (or dirs (project-roots project))))
+
+(defun project--vc-list-files (dir backend extra-ignores)
+  (pcase backend
+    (`Git
+     (let ((default-directory dir)
+           (args '("-z")))
+       ;; Include unregistered.
+       (setq args (append args '("-c" "-o" "--exclude-standard")))
+       (when extra-ignores
+         (setq args (append args
+                            (cons "--"
+                                  (mapcar
+                                   (lambda (i)
+                                     (if (string-match "\\./" i)
+                                         (format ":!/:%s" (substring i 2))
+                                       (format ":!:%s" i)))
+                                   extra-ignores)))))
+       (mapcar
+        (lambda (file) (concat dir file))
+        (split-string
+         (apply #'vc-git--run-command-string nil "ls-files" args)
+         "\0" t))))
+    (`Hg
+     (let ((default-directory dir)
+           args
+           files)
+       ;; Include unregistered.
+       (setq args (nconc args '("--all")))
+       (when extra-ignores
+         (setq args (nconc args
+                           (mapcan
+                            (lambda (i)
+                              (list "--exclude" i))
+                            (copy-list extra-ignores)))))
+       (with-temp-buffer
+         (apply #'vc-hg-command t 0 "."
+                "status" args)
+         (goto-char (point-min))
+         (while (re-search-forward "^[?C]\s+\\(.*\\)$" nil t)
+           (setq files (cons (concat dir (match-string 1))
+                             files))))
+       (nreverse files)))))
+
 (cl-defmethod project-ignores ((project (head vc)) dir)
   (let* ((root (cdr project))
           backend)
@@ -391,7 +451,8 @@ pattern to search for."
        (status nil)
        (hits nil)
        (xrefs nil)
-       (command (format "xargs -0 grep %s -nHE -e %s"
+       ;; 'git ls-files' can output broken symlinks.
+       (command (format "xargs -0 grep %s -snHE -e %s"
                         (if (and case-fold-search
                                  (isearch-no-upper-case-p regexp t))
                             "-i"