From 2a46d758f71dc6d8e13b7ff307f18d82e9d9941f Mon Sep 17 00:00:00 2001 From: ambihelical Date: Sat, 15 Jul 2017 15:15:09 -0700 Subject: [PATCH] Improve counsel-projectile-find-file performance Current code will show significant lag for projects with large numbers of files. Tests with 400K files shows 15-20s lag for counsel-projectile-find-file. Profiling showed that this was due to the preprocessing of projectile-current-project-files to add 'ivy-virtual face to files not already in a buffer. To fix this, a display transformer was added for this command so that the face modification was applied only to at most ivy-height files. The preprocessed file list was also used by counsel-projectile code paths, so some additional modifications were made to ensure that that code path does not change behavior. Any similar issues in counsel-projectile performance was not addressed in this commit. Details: * move 'ivy-virtual face change to a display transformer function * use projectile-current-project-files instead of counsel-projectile--file-list for ivy-read. * reduce the scope of counsel-projectile--file-list, making it return only unvisited files, and renaming it accordingly. This is now only used indirectly by the counsel-projectile function. * change ivy-switch-buffer-transformer to propertize files at display time. --- counsel-projectile.el | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/counsel-projectile.el b/counsel-projectile.el index f3ae6ca..214fa94 100644 --- a/counsel-projectile.el +++ b/counsel-projectile.el @@ -65,20 +65,16 @@ ;;; counsel-projectile-find-file -(defun counsel-projectile--file-list (&optional no-buffer) - "Return a list of files for the current project. +(defun counsel-projectile--unvisited-file-list () + "Return a list of unvisited files for the current project. -Like `projectile-current-project-files', but fontifies -non-visited file names with the `ivy-virtual' face. With optional -argument NO-BUFFER, only list non-visited files." +Like `projectile-current-project-files', but skips any files +already being visited by a buffer." (let ((root (projectile-project-root))) (cl-loop for name in (projectile-current-project-files) for file = (expand-file-name name root) if (not (get-file-buffer file)) - collect (propertize name 'face 'ivy-virtual) - else - unless no-buffer collect name))) (defun counsel-projectile--find-file-action (file &optional other-window) @@ -94,6 +90,12 @@ argument NO-BUFFER, only list non-visited files." `projectile-find-file-hook'." (counsel-projectile--find-file-action file t)) +(defun counsel-projectile--find-file-transformer (name) + "Transform non-visited file names with `ivy-virtual' face." + (if (not (get-file-buffer (expand-file-name name (projectile-project-root)))) + (propertize name 'face 'ivy-virtual) + name)) + ;;;###autoload (defun counsel-projectile-find-file (&optional arg) "Jump to a project's file using completion. @@ -103,7 +105,7 @@ invalidates the cache first." (interactive "P") (projectile-maybe-invalidate-cache arg) (ivy-read (projectile-prepend-project-name "Find file: ") - (counsel-projectile--file-list) + (projectile-current-project-files) :matcher #'counsel--find-file-matcher :require-match t :keymap counsel-projectile-map @@ -115,6 +117,10 @@ invalidates the cache first." '(("j" counsel-projectile--find-file-other-window-action "other window"))) +(ivy-set-display-transformer + 'counsel-projectile-find-file + 'counsel-projectile--find-file-transformer) + ;;; counsel-projectile-find-dir (defun counsel-projectile--dir-list () @@ -370,15 +376,17 @@ invokes `projectile-commander' instead of (counsel-projectile--buffer-list)) (mapc (lambda (file) (add-text-properties 0 1 '(type file) file)) - (counsel-projectile--file-list t)))) + (counsel-projectile--unvisited-file-list)))) (defun counsel-projectile--transformer (str) "Fontifies modified, file-visiting buffers. Relies on `ivy-switch-buffer-transformer'." - (if (eq (get-text-property 0 'type str) 'buffer) - (ivy-switch-buffer-transformer str) - str)) + (let ((type (get-text-property 0 'type str))) + (cond + ((eq type 'buffer) (ivy-switch-buffer-transformer str)) + ((eq type 'file) (propertize str 'face 'ivy-virtual)) + (t str)))) (defun counsel-projectile--matcher (regexp candidates) "Return REGEXP-matching CANDIDATES.