The Missing Piece to helm-projectile

Obviously you should be able to start a search by choosing a directory in the current project and then doing a recursive grep from there.

But for some reason that’s not built into helm-projectile or helm-rg, my preferred search interface.

So after like several months of living with this hole in my life, I took an hour and wrote it. I didn’t know it would only take an hour, of course, otherwise I probably would have done it sooner. I haven’t written much emacs lisp, so I figured it could be a little bit of a struggle. But in the end it wasn’t too hard to find the functions I needed by reading the helm-rg code and the projectile code. Especially since helm-rg has a function called helm-rg--set-dir which does mostly the same thing, except the interface is not as smooth as I would like.

The interface I would like is this:

  • Start a projectile folder search through the current project w/ a super convenient keybinding. Maybe SPC d /.
  • Find the folder you want to treat as the root of your search. The important part here is that it’s a fuzzy search. You should only need to type enough characters to select the folder you’re looking for from all the rest.
  • Select the folder. This will start a string search using whatever tool you have set up to do your grepping (like I said, I like to use helm-rg cuz it’s super fast).

Looking through the projectile.el source code, I found two functions that do all the heavy lifting for this feature: projectile-complete-dir and projectile-acquire-root.

projectile-complete-dir takes a directory as its only argument and presents you with a helm popup where you can use fuzzy search to select a folder below that directory. This is what we use to quickly pick the search root.

projectile-acquire-root takes no arguments, and uses the current buffer to find the project root. You just call it from wherever you are and it finds the nearest ancestor directory that has a .git file.

By combining these two it was pretty easy to write a function that runs my desired behavior.

(defun mpr/helm-rg-from-dir ()
    (interactive)
    (let ((helm-rg--current-dir
              (expand-file-name
                (projectile-complete-dir (projectile-acquire-root))
                (projectile-acquire-root))))
      (helm-rg helm-pattern)))

And then I bound it to the convenient SPC d / like I mentioned above.

(evil-define-key 'normal (kbd "SPC d /") 'mpr/helm-rg-from-dir)
Matt Roll @mroll