<feed xmlns='http://www.w3.org/2005/Atom'>
<title>projectile.git, branch master</title>
<subtitle>Unnamed repository; edit this file 'description' to name the repository.
</subtitle>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/'/>
<entry>
<title>Coalesce idle-timer flushes in projectile-cache-current-file</title>
<updated>2026-04-27T07:58:28+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-27T07:58:28+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=28014dae7034fff49f5740b013a426aade7873f3'/>
<id>28014dae7034fff49f5740b013a426aade7873f3</id>
<content type='text'>
Each call to `projectile-cache-current-file' under persistent caching
scheduled a fresh 30-second idle timer that closed over a snapshot of
the file list at scheduling time.  Opening N files in a session
queued N timers; once Emacs went idle they all fired and serialized
the cache N times, with the earlier ones writing stale (shorter)
lists.

Maintain a per-project pending timer in
`projectile--pending-cache-flush-timers' instead, cancelling and
rescheduling on each new file.  The fired callback re-reads the
current in-memory cache, so the disk write reflects the final state
rather than whichever snapshot the last timer captured.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Each call to `projectile-cache-current-file' under persistent caching
scheduled a fresh 30-second idle timer that closed over a snapshot of
the file list at scheduling time.  Opening N files in a session
queued N timers; once Emacs went idle they all fired and serialized
the cache N times, with the earlier ones writing stale (shorter)
lists.

Maintain a per-project pending timer in
`projectile--pending-cache-flush-timers' instead, cancelling and
rescheduling on each new file.  The fired callback re-reads the
current in-memory cache, so the disk write reflects the final state
rather than whichever snapshot the last timer captured.
</pre>
</div>
</content>
</entry>
<entry>
<title>Delete cache file in projectile-invalidate-cache</title>
<updated>2026-04-27T07:50:40+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-27T07:50:40+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=d8bbeedd275cea4765555c731b265ce7757ad9e5'/>
<id>d8bbeedd275cea4765555c731b265ce7757ad9e5</id>
<content type='text'>
Previously the persistent invalidate path called
`(projectile-serialize nil ...)', leaving a four-byte file containing
the literal "nil" on disk.  Resolving the long-standing TODO: just
delete the file when invalidating, so the on-disk state matches the
intent of the command (and so an orphaned cache file isn't left
behind on uninstall).
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Previously the persistent invalidate path called
`(projectile-serialize nil ...)', leaving a four-byte file containing
the literal "nil" on disk.  Resolving the long-standing TODO: just
delete the file when invalidating, so the on-disk state matches the
intent of the command (and so an orphaned cache file isn't left
behind on uninstall).
</pre>
</div>
</content>
</entry>
<entry>
<title>Persist disk cache in projectile-purge-dir-from-cache</title>
<updated>2026-04-27T07:48:07+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-27T07:48:07+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=fc8559850228f54efbc7ee4ea56b2e376cec5b04'/>
<id>fc8559850228f54efbc7ee4ea56b2e376cec5b04</id>
<content type='text'>
`projectile-purge-file-from-cache' writes the updated file list to
disk under persistent caching; the directory variant only mutated
the in-memory hash, so the purged subtree would reappear on the
next Emacs session.  Mirror the persistence step here.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
`projectile-purge-file-from-cache' writes the updated file list to
disk under persistent caching; the directory variant only mutated
the in-memory hash, so the purged subtree would reappear on the
next Emacs session.  Mirror the persistence step here.
</pre>
</div>
</content>
</entry>
<entry>
<title>Seed cache time when loading the project file cache from disk</title>
<updated>2026-04-27T01:27:35+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-27T01:27:35+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=a55eeb2b1821c5252a5ea3d8c7c79728a42763fe'/>
<id>a55eeb2b1821c5252a5ea3d8c7c79728a42763fe</id>
<content type='text'>
Without this, `projectile-files-cache-expire' combined with persistent
caching ended up re-reading the cache file from disk on every call to
`projectile-project-files' and never reindexing: the TTL check at the
top of `projectile-project-files' evicts the in-memory entry whenever
its cache time is missing, and `projectile-load-project-cache' was
populating only `projectile-projects-cache' on disk loads.  Use the
cache file's mtime as the recorded time, so the TTL check sees a real
age and reindexing happens when (and only when) the data is actually
stale.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Without this, `projectile-files-cache-expire' combined with persistent
caching ended up re-reading the cache file from disk on every call to
`projectile-project-files' and never reindexing: the TTL check at the
top of `projectile-project-files' evicts the in-memory entry whenever
its cache time is missing, and `projectile-load-project-cache' was
populating only `projectile-projects-cache' on disk loads.  Use the
cache file's mtime as the recorded time, so the TTL check sees a real
age and reindexing happens when (and only when) the data is actually
stale.
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge pull request #2000 from bbatsov/indexing-cleanup-final</title>
<updated>2026-04-26T11:34:26+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@batsov.dev</email>
</author>
<published>2026-04-26T11:34:26+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=67c18e26fe68552a273b7794451ce757cc3afe9a'/>
<id>67c18e26fe68552a273b7794451ce757cc3afe9a</id>
<content type='text'>
Final indexing review batch: cleanup, tests, docs</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Final indexing review batch: cleanup, tests, docs</pre>
</div>
</content>
</entry>
<entry>
<title>Document remaining indexing semantics</title>
<updated>2026-04-26T11:30:10+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-26T11:30:10+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=a039e44622b644deb90893f7b27c0940c486bbb7'/>
<id>a039e44622b644deb90893f7b27c0940c486bbb7</id>
<content type='text'>
Three doc gaps surfaced during the indexing review:

* The `*' prefix on `projectile-globally-ignored-directories' entries
  is not a glob - it is what promotes a basename match from
  "anchored at the project root" to "anywhere in the tree", and it
  only takes effect under hybrid indexing.
* The default `projectile-generic-command' picks `fd' when it's on
  PATH and falls back to a `find ... | tr ...' pipeline. The
  fallback does not exclude common build directories, which is a
  trap for non-VCS projects under alien on hosts without `fd'.
* `projectile-git-use-fd' controls how Projectile handles
  deleted-but-unstaged files: with `fd' they disappear immediately,
  with `git ls-files' Projectile post-filters via `git ls-files -zd'.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Three doc gaps surfaced during the indexing review:

* The `*' prefix on `projectile-globally-ignored-directories' entries
  is not a glob - it is what promotes a basename match from
  "anchored at the project root" to "anywhere in the tree", and it
  only takes effect under hybrid indexing.
* The default `projectile-generic-command' picks `fd' when it's on
  PATH and falls back to a `find ... | tr ...' pipeline. The
  fallback does not exclude common build directories, which is a
  trap for non-VCS projects under alien on hosts without `fd'.
* `projectile-git-use-fd' controls how Projectile handles
  deleted-but-unstaged files: with `fd' they disappear immediately,
  with `git ls-files' Projectile post-filters via `git ls-files -zd'.
</pre>
</div>
</content>
</entry>
<entry>
<title>Backfill tests for indexing command dispatch</title>
<updated>2026-04-26T11:29:59+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-26T11:29:59+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=366049b8f4a14fc1842ae264e6544bdc279308b5'/>
<id>366049b8f4a14fc1842ae264e6544bdc279308b5</id>
<content type='text'>
`projectile-get-ext-command' had no direct test coverage, so the
non-git VCS branches (hg/svn/bzr/darcs/fossil/pijul/sapling/jj) were
relying on indirect coverage that didn't actually exercise the
dispatch. Add a `describe' block that pins each branch.

Also extend the `projectile-dir-files-alien' tests with two cases
that were previously uncovered: the fd path for git (verifying we
don't also call `projectile-git-deleted-files') and the no-VCS
fallback (verifying the generic command is used).
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
`projectile-get-ext-command' had no direct test coverage, so the
non-git VCS branches (hg/svn/bzr/darcs/fossil/pijul/sapling/jj) were
relying on indirect coverage that didn't actually exercise the
dispatch. Add a `describe' block that pins each branch.

Also extend the `projectile-dir-files-alien' tests with two cases
that were previously uncovered: the fd path for git (verifying we
don't also call `projectile-git-deleted-files') and the no-VCS
fallback (verifying the generic command is used).
</pre>
</div>
</content>
</entry>
<entry>
<title>Skip git submodule scan when there is no .gitmodules</title>
<updated>2026-04-26T11:29:52+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-26T11:29:52+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=ccd8052beb84a889565ffd08a58cf643e2e439f3'/>
<id>ccd8052beb84a889565ffd08a58cf643e2e439f3</id>
<content type='text'>
`projectile-get-immediate-sub-projects' was unconditionally shelling
out to `git submodule --quiet foreach ...' on every indexing call for
git projects, even when the project had no submodules at all. For
monorepos that re-index the project root often this is pure overhead.

Use `locate-dominating-file' to look for `.gitmodules' along the
parent chain (PATH may be inside a git repo without being its
toplevel) and skip the shell-out when none is found.

Also tighten `projectile-discover-projects-in-directory' to filter
`.' / `..' via `directory-files-no-dot-files-regexp' instead of a
post-filter `member' check, matching the indexing walker's style.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
`projectile-get-immediate-sub-projects' was unconditionally shelling
out to `git submodule --quiet foreach ...' on every indexing call for
git projects, even when the project had no submodules at all. For
monorepos that re-index the project root often this is pure overhead.

Use `locate-dominating-file' to look for `.gitmodules' along the
parent chain (PATH may be inside a git repo without being its
toplevel) and skip the shell-out when none is found.

Also tighten `projectile-discover-projects-in-directory' to filter
`.' / `..' via `directory-files-no-dot-files-regexp' instead of a
post-filter `member' check, matching the indexing walker's style.
</pre>
</div>
</content>
</entry>
<entry>
<title>Merge pull request #1999 from bbatsov/indexing-perf</title>
<updated>2026-04-26T11:17:14+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@batsov.dev</email>
</author>
<published>2026-04-26T11:17:14+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=fa890caa2b21af3895b302e22e1d74df8ee55453'/>
<id>fa890caa2b21af3895b302e22e1d74df8ee55453</id>
<content type='text'>
Speed up indexing's ignore filtering</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Speed up indexing's ignore filtering</pre>
</div>
</content>
</entry>
<entry>
<title>Add tests for the indexing fast-path helpers</title>
<updated>2026-04-26T11:13:04+00:00</updated>
<author>
<name>Bozhidar Batsov</name>
<email>bozhidar@toptal.com</email>
</author>
<published>2026-04-26T11:13:04+00:00</published>
<link rel='alternate' type='text/html' href='http://git.tews.dev/cgit/projectile.git/commit/?id=ca5c96f6ed9d203f22f6d41a862449480dc46aec'/>
<id>ca5c96f6ed9d203f22f6d41a862449480dc46aec</id>
<content type='text'>
Cover the new internal helpers (`projectile--list-&gt;set',
`projectile--ignored-file-fast-p', `projectile--ignored-directory-
fast-p') and add end-to-end tests for the previously uncovered
behaviour:

* `projectile-index-directory' honors dirconfig glob ignore patterns
  at every directory level - previously only the alien-mode dirconfig
  warning had any test coverage for this.
* Ensure (`!') entries in `.projectile' override an ignore pattern.
* `projectile-remove-ignored' drops basename matches, treats `*'-
  prefixed ignored-dir entries as any-segment matches, and treats
  plain entries as path-prefix matches.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Cover the new internal helpers (`projectile--list-&gt;set',
`projectile--ignored-file-fast-p', `projectile--ignored-directory-
fast-p') and add end-to-end tests for the previously uncovered
behaviour:

* `projectile-index-directory' honors dirconfig glob ignore patterns
  at every directory level - previously only the alien-mode dirconfig
  warning had any test coverage for this.
* Ensure (`!') entries in `.projectile' override an ignore pattern.
* `projectile-remove-ignored' drops basename matches, treats `*'-
  prefixed ignored-dir entries as any-segment matches, and treats
  plain entries as path-prefix matches.
</pre>
</div>
</content>
</entry>
</feed>
