diff options
| author | Bozhidar Batsov <bozhidar@batsov.dev> | 2026-02-28 08:42:17 +0200 |
|---|---|---|
| committer | Bozhidar Batsov <bozhidar@batsov.dev> | 2026-02-28 08:54:10 +0200 |
| commit | 8f4a1f71cb9211229702d16e89c1c2e2cf31173f (patch) | |
| tree | 70f05b5c5093a018b40522c88b35fb1a0a255dcc /projectile.el | |
| parent | b5936d67c70f5d18094d31eb488304a9a0be8d16 (diff) | |
Cache projectile-parse-dirconfig-file results per project
The .projectile dirconfig file was being re-read and re-parsed 3-4
times per indexing operation (by paths-to-ignore, patterns-to-ignore,
paths-to-ensure, patterns-to-ensure, etc.). This is wasteful,
especially over TRAMP where each file read is a network round-trip.
Cache the parsed result per project root, keyed by the file's
modification time so edits to .projectile are picked up immediately.
The cache is also cleared by projectile-invalidate-cache.
Diffstat (limited to 'projectile.el')
| -rw-r--r-- | projectile.el | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/projectile.el b/projectile.el index d35df00..5323db0 100644 --- a/projectile.el +++ b/projectile.el @@ -1119,6 +1119,7 @@ argument)." (remhash project-root projectile-project-type-cache) (remhash project-root projectile-projects-cache) (remhash project-root projectile-projects-cache-time) + (remhash project-root projectile--dirconfig-cache) ;; reset the project's cache file (when (projectile-persistent-cache-p) ;; TODO: Perhaps it's better to delete the cache file in such cases? @@ -2127,18 +2128,13 @@ Unignored files/directories are not included." "Return the absolute path to the project's dirconfig file." (expand-file-name projectile-dirconfig-file (projectile-project-root))) -(defun projectile-parse-dirconfig-file () - "Parse project ignore file and return directories to ignore and keep. +(defvar projectile--dirconfig-cache (make-hash-table :test 'equal) + "Cache for parsed dirconfig files, keyed by project root. +Each value is a cons of (MTIME . PARSED-RESULT).") -The return value will be a list of three elements, the car being -the list of directories to keep, the cadr being the list of files -or directories to ignore, and the caddr being the list of files -or directories to ensure. - -Strings starting with + will be added to the list of directories -to keep, and strings starting with - will be added to the list of -directories to ignore. For backward compatibility, without a -prefix the string will be assumed to be an ignore string." +(defun projectile--parse-dirconfig-file-uncached () + "Parse the dirconfig file without caching. +Returns a list of (KEEP IGNORE ENSURE) or nil if the file doesn't exist." (let (keep ignore ensure (dirconfig (projectile-dirconfig-file))) (when (projectile-file-exists-p dirconfig) (with-temp-buffer @@ -2163,6 +2159,31 @@ prefix the string will be assumed to be an ignore string." (mapcar #'string-trim (delete "" (reverse ensure))))))) +(defun projectile-parse-dirconfig-file () + "Parse project ignore file and return directories to ignore and keep. + +The return value will be a list of three elements, the car being +the list of directories to keep, the cadr being the list of files +or directories to ignore, and the caddr being the list of files +or directories to ensure. + +Strings starting with + will be added to the list of directories +to keep, and strings starting with - will be added to the list of +directories to ignore. For backward compatibility, without a +prefix the string will be assumed to be an ignore string. + +Results are cached per project root and invalidated when the +dirconfig file's modification time changes." + (let* ((dirconfig (projectile-dirconfig-file)) + (project-root (projectile-project-root)) + (cached (gethash project-root projectile--dirconfig-cache)) + (mtime (file-attribute-modification-time (file-attributes dirconfig)))) + (if (and cached (equal (car cached) mtime)) + (cdr cached) + (let ((result (projectile--parse-dirconfig-file-uncached))) + (puthash project-root (cons mtime result) projectile--dirconfig-cache) + result)))) + (defun projectile-expand-root (name &optional dir) "Expand NAME to project root. When DIR is specified it uses DIR's project, otherwise it acts |
