bling / fzf.el

A front-end for fzf
GNU General Public License v3.0
369 stars 50 forks source link

Grepping text inside of another directory using fzf+rg #72

Closed raresvis closed 2 years ago

raresvis commented 2 years ago

Hi!

Thanks for the project!

Often times I need to search for specific strings in other directories. The fzf-grep command will perform the search, but only in the current directory.

So the requirements are:

The former is fixed easily, just ask the user for a directory. To accomodate for the second requirement, I used the commands shown in the Interactive ripgrep integration section from the fzf repo [1].

My solution so far is a bit hacky, but it works. It looks like this:

(defun fzf-grep-in-dir ()
  (interactive)
  (let ((fzf/args "-x --color bw --print-query --margin=1,0 --no-hscroll --bind \"change:reload:rg --column --line-number --no-heading --smart-case {q} || true\" ")
        (action #'fzf/action-find-file-with-line)
        (dir (read-directory-name "Directory: " fzf/directory-start)))
    ;;(fzf-with-command "rg --column --line-number --no-heading --smart-case ''" action dir)
    (fzf/start dir action "rg --column --line-number --no-heading --smart-case ''")
    ))

The fzf-with-command function can be used instead of fzf/start, since the former is just a wrapper around the latter.

Is there a better alternative to this that could be implemented in fzf.el in the future?

Thanks!

ghost commented 2 years ago

Hi @raresvis - I'll answer in parts

  1. Grep in another directory The solution for this would be to prompt the user for a directory, just as you've done
  2. Use Ripgrep instead of grep I added functionality for this in this commit. You can change the default command used for fzf-grep-* functions by customizing the fzf/grep-command to whatever you'd like. For ripgrep you would need to (at least) pass these options: rg --no-heading -nH (this is included in the use-package section of the README for reference). The important part is that the fzf/action-find-file-with-line can parse the output. It currently expects something like FILE:LINUM:....

I can add an fzf-grep-in-dir command that will use fzf/grep-command and prompt the user for the directory to search in. That way all you'd need to do is set fzf/grep-command accordingly and the rest will be handled by the package.

Can you confirm that the functionality that I've described is what you're looking for, or are you asking for fzf to launch ripgrep interactively and dynamically update the list (like the example you've linked).

raresvis commented 2 years ago

Hi @sayeefm0! Thanks for the fast reply.

or are you asking for fzf to launch ripgrep interactively and dynamically update the list (like the example you've linked).

Yep, this is exactly the desired outcome.

ghost commented 2 years ago

Gotcha. I'll have a go at it in the next few days : )

ghost commented 2 years ago

Hey @raresvis, I just sent a PR for this: https://github.com/bling/fzf.el/pull/73

In the meantime if you want to get on ahead using it, you can try using my fork. The commands you're looking for are fzf-grep-with-narrowing and fzf-grep-in-dir-with-narrowing. Both of these will use fzf/grep-command, so if you'd like to use rg see my comments above about setting that var.

fzf-grep-with-narrowing behaves like fzf-grep but uses fzf/grep-command to incrementally narrow the search space, and fzf-grep-in-dir-with-narrowing does the same but asks you for a dir first. I also went ahead and added an fzf-grep-in-dir which DOES NOT use grep for narrowing, but seemed like it should be there for good measure.

raresvis commented 2 years ago

Thank you so much for this @sayeefm0! Looks great!

bling commented 2 years ago

73 merged.