If you’re like me, you’ve been patiently enduring cluttered projectile search results for a long time. Results from HTML files you don’t care about, or temporary files, or third party files that you .. don’t .. even, just because all of these happen to exist in your source repo folder. Well, after many months of this subtle incitement to murder, I decided to finally spend some time improving this very-frequently-used part of my workflow, i.e. project tree grep search. So here’s looking at you, next person. May these settings help you claw your way back toward sanity.
TL;DR: I used ripgrep
instead of grep
, with a .ignore
file to specify search excludes (scroll down for config).
The substance of the issue is that projectile allows you to specify files and paths to be included or excluded from searches in a .projectile
file, but, it turns out, this file is consulted only when using projectile’s “native” indexing method, which is unusably slow. The “alien” indexing method, on the other hand, allows projectile to just ask the version control system for the project’s list of files instead of computing it from scratch, and is much faster. But this method disregards any “ignore” config you put in the .projectile
config file, resulting in cluttered search results.
The solution I ended up going with was to retain the default “alien” indexing method and configure the excludes not at the indexing step but rather at the search step.
My setup
- Instead of
projectile-grep
, useprojectile-ripgrep
. Both of these are part of projectile and you should already have them. - Install ripgrep on your system as well as the
ripgrep
(notrg
) Emacs package. - Add a
.ignore
(or equivalently,.rgignore
) file in your project root directory, which is formatted essentially the same as.gitignore
. This indicates files/folders that you want to exclude from searches, even if they are present in your git repo.
Example Ignore Config
*.html
a_folder_to_ignore/
You can even use this file to whitelist patterns that are otherwise ignored in your .gitignore
(Ripgrep implicitly inherits ignores from .gitignore
if one is present). See the ripgrep user manual for more on how to use this file.
That’s it. Enjoy clean, wonderful, unimpeachable (and fast) search results.
Learnings
Recursive text search is a very common operation, not really specific to the notion of “projects.” For this reason, I think it makes sense to use a purpose-built tool for the job rather than necessarily rely on projectile (especially projectile’s native method). For this, there are many alternatives available such as rg.el and ripgrep.el (these seem very similar), ag.el, deadgrep, and even Emacs’s built-in rgrep, and minibuffer-based options like counsel-rg
provided by the counsel library. If any of these options works for you, you could remap your current project search keybinding to use one of these tools. Especially with the .rgignore
/.ignore
file, any of these could become very viable alternatives to projectile search. They do have slightly different interfaces though, for better or worse. For instance, some people seem to really like deadgrep’s interface. I personally found the rg / ripgrep interfaces easier to parse visually, but that could be because I’m color blind. In any case, armed with your .rgignore
, I encourage you to give all of these a shot!
Other options
You could also use the version of projectile-ripgrep
from this file to override the one provided by projectile itself. From the sounds of it, this would get around the native
-only limitation mentioned at the beginning of this post. That is, it would allow you to use your existing .projectile
ignores while searching with projectile-ripgrep
. I tried it and ran into some unexpected behavior, but YMMV.