
How FZF and ripgrep improved my workflow - daddy_drank
https://medium.com/@sidneyliebrand/how-fzf-and-ripgrep-improved-my-workflow-61c7ca212861
======
yaantc
Fuzzy down selection (fzf) is the big win. In Emacs that would be Helm of
swiper. Instead of local completion (tab tab tab ;) do a global search, and
narrow down interactively using fuzzy selection. It's really a different
experience, a bit disconcerting at first (tab built into muscle memory), but
it quickly becomes a one way change. No way I'd let go of fuzzy selection now.

The connection with ripgrep is that fuzzy selection works well when getting
all the possible candidates is fast. And ripgrep (or sd) is good for that. So
there's a connection, but the big change is really moving to fuzzy down
selection. When dealing with large context it really makes a difference in
productivity in my experience, because it helps a lot discoverability in a
smooth and efficient way.

For a GUI alternative to fzf, one can look at rofi.

~~~
fluffything
> but it quickly becomes a one way change.

I've been using Helm for a couple of years, and it has crippled all other
editors and IDEs for me.

I never read the manual, I have no idea how Helm works, or what it does, or
what it is supposed to do. Yet I do use it all day every day. I just type, and
Helm delivers what I meant, blazingly fast.

I've tried Atom, VSCode, Eclipse, CLion, Visual Studio, Xcode... I can't use
them. You have to click on tabs to switch, you have to click dialogs to open
views of the file system, and then navigate them to where you want to go,
manually search for the file you want, actually use search boxes somewhere...
they all feel super ancient UI wise. Sure, Atom, VSCode, Sublime, they all
have some magic box where you can do anything, but that box just isn't Helm.

With Helm I know there is a file or a buffer or anything somewhere containing
something that I might need and I don't even know what it is, and I just start
pressing keys and Helm goes from showing me the whole universe, to pin
pointing me the grain of sand that I didn't know I wanted, by interacting with
me.

I have no idea how to even start Helm, nor which keys I press there. Do I
press Tab? Sure. What do I press to start interacting with helm ? I don't even
know, it just happens. Best tool ever.

~~~
luckman212
Sounds amazing. Would [https://github.com/emacs-
helm/helm/blob/master/README.md](https://github.com/emacs-
helm/helm/blob/master/README.md) be the correct starting point for learning
more about Helm?

~~~
vindarel
Yes. I also like

\- [http://wikemacs.org/wiki/Helm](http://wikemacs.org/wiki/Helm) and
[http://wikemacs.org/wiki/Helm-swoop](http://wikemacs.org/wiki/Helm-swoop)

\- which link to an extensive tutorial: [https://tuhdo.github.io/helm-
intro.html](https://tuhdo.github.io/helm-intro.html)

and +1 for Spacemacs: [http://spacemacs.org/](http://spacemacs.org/) (see
other starter kits:
[http://wikemacs.org/wiki/Starter_Kits](http://wikemacs.org/wiki/Starter_Kits)

------
ronjouch
I also use fzf as git branch picker :)

In my fish_user_key_bindings.fish (but surely adaptable to other shells), I
bind it to Alt+G:

    
    
        function fish_user_key_bindings
            bind \eg 'test -d .git; and git checkout (string trim -- (git branch | fzf)); and commandline -f repaint'
            bind \eG 'test -d .git; and git checkout (string trim -- (git branch --all | fzf)); and commandline -f repaint'
        end
    

This goes neatly with fzf's default Alt+C binding to navigate to a directory:
Alt+C -> go to a git repo, followed by Alt+G -> pick a branch

~~~
vbsteven
In Bash/Zsh you can do it with `git config --global alias.cof $'!git for-each-
ref --format=\''%\\(refname:short\\)\'' refs/heads | fzf | xargs git
checkout'`

and then do a checkout with `git cof`

------
roryrjb
I can't really fault both of these tools at all. They have good defaults and
are easy to configure and are well documented. Of course they are very
performant too, but if you take the time to configuring your wildignore, learn
how to use find's and rgrep's flags (maybe script some of this with shell or
vimscript if necessary) you can get close to the performance of these tools
and define your own usability if needed. Basically I'm saying two things and
can I just state that this is what works for _me_ ; that learning the included
tools is worthwhile and not having to install and setup additional tools is
good, especially when you are using lots of different machines. Again for Vim
specifically, I'm enjoying having a small amount of keybindings for built in
functionality (:b*, :vimgrep) than having a ton of plugins. I just have to
move a single .vimrc around or failing that I understand how it all works by
default anyway.

(Edit: typo)

~~~
iamnotacrook
Not to argue with you as I see where you're coming from (all things being
equal I too usually go with the defaults) but the argument about "not having
to install and setup additional tools...on lots of different machines" is very
weak in these days of:

git clone
[https://gitlab.com/myaccount/mydotfiles](https://gitlab.com/myaccount/mydotfiles)

followed by an optional:

./deploy_stuff_if_required

which for me I have working on any number of linux boxes as well as the odd
windows one. I've got a bunch of other config, such as bash aliases/functions
etc anyway so if I'm going to want that everywhere it doesn't matter what else
comes with it; I only need to perform the above once and it takes under a
couple of seconds; there's just literally no reason not to do it.

One advantage of using vim-related config is precisely so you can do the same
thing on different machines, including windows and linux. One thing that
article doesn't touch on is tmux, and there you can have config for vim, tmux
and bash so that you can effortlessly and identically move between panes in
tmux as you do in vim; copy text between panes, ssh sessions and vim buffers
etc. Without this system I'd be running multiple ssh sessions in little
windows and copying text between them (using the mouse!) like a doofus.

~~~
saagarjha
Note that not every machine I SSH into has git installed or provides me with
permission to install it.

Disclaimer: I recently made one of these "dotfiles" repositories anyways, to
take of that what you will.

~~~
Liquid_Fire
Assuming it's hosted on something like GitHub, you can just as easily download
a zip/tarball of the repository instead.

~~~
saagarjha
A copy is, so I can grab my bashrc if I need it. However, it’s still
impossible to install things on certain systems…

~~~
kspp
If it's the "too complicated to bother" sort of "impossible" as opposed to
"denied by the company security policies", you can always use linuxbrew or
nix.

[https://docs.brew.sh/Homebrew-on-Linux](https://docs.brew.sh/Homebrew-on-
Linux)

[https://nixos.org/nix/](https://nixos.org/nix/)

------
simonw
Fun fact about ripgrep: it's built into Visual Studio Code - it's why the
"find in files" feature runs so fast.

Which means that if you run VS Code on OS X you actually have ripgrep
installed already - just run the following:

    
    
        /Applications/Visual\ Studio\ Code.app/Contents/Resources/app/node_modules.asar.unpacked/vscode-ripgrep/bin/rg

------
Avi-D-coder
Shameless plug FZF even works well as a dictionary/word autocompleter.
[https://github.com/Avi-D-coder/fzf-wordnet.vim](https://github.com/Avi-D-
coder/fzf-wordnet.vim)

~~~
petepete
Neat. I use it for all kinds of stuff in Rails Feb, from searching routes and
rake tasks to finding Cucumber step definitions.

I'd recommend using fd for listing files as it offers lots of filtering
options right out of the box - much more useable than find imho.

[https://github.com/sharkdp/fd](https://github.com/sharkdp/fd)

~~~
petepete
I can't edit now, but that was typed on my phone and it autocorrected 'dev' to
'Feb'. Amazing.

------
wincent
See also Skim (fzf-a-like written in Rust):

[https://github.com/lotabout/skim](https://github.com/lotabout/skim)

I like the result ordering better than fzf, and it has a neat interactive
mode.

------
matthewfelgate
I'm pretty junior at coding but I find FZF great.

    
    
      Ctrl-r for shell history
      Ctrl-t for file search
    

Especially writing `code` and then ctrl-t, finding the file and then enter to
open it in visual studio.

Game changer.

~~~
sakisv
Ctrl-t is a game changer, thank you for sharing this, I only knew the
<star><star><TAB> notation.

~~~
chewz
export FZF_COMPLETION_TRIGGER='' and you don't need <star><star> just <TAB>

------
hwj
fzy[1], which is written in C, seems to be slightly faster:

    
    
        $ hyperfine --warmup 2 -r 10 'rg --files | fzy -e hello'  'rg --files | fzf -f hello'
        Benchmark #1: rg --files | fzy -e hello
          Time (mean ± σ):     153.6 ms ±  57.9 ms    [User: 399.2 ms, System: 96.9 ms]
          Range (min … max):    85.9 ms … 244.3 ms    10 runs
         
        Benchmark #2: rg --files | fzf -f hello
          Time (mean ± σ):     210.5 ms ±  61.6 ms    [User: 443.3 ms, System: 90.9 ms]
          Range (min … max):   123.3 ms … 315.5 ms    10 runs
         
        Summary
          'rg --files | fzy -e hello' ran
            1.37 ± 0.65 times faster than 'rg --files | fzf -f hello'
    
    

[1] [https://github.com/jhawthorn/fzy](https://github.com/jhawthorn/fzy)

~~~
yaantc
There's a big difference in how their matching works, that made me prefer fzf.
It's related to how they deal with spaces.

With fzf, and also helm in Emacs, rofi... a space is a separator between
matchers, and the order of the matchers does not matter. So if you type "foo
bar", it will select a path "/bar/bla/foo" just fine. This is important to me
for discoverability: very often you know quite well what keywords to look for,
but you don't know or are not sure about the order. So order irrelevance is
very important.

fzy treats the space as a literal. So the order matters. And that's a killer
for me. Plus in my experience the speed difference is not important, all are
fast enough in practice.

~~~
hwj
Thanks for pointing this out. I guess fzy's primary goal is path matching
which might explain this behaviour.

------
apexalpha
Fzf is one of those tools I learned about and instantly became one of the
things you can't go without anymore.

------
Galanwe
Been using linux for 15 years and I never found any use case for all these
fancy grep/ctrl+r/find replacements.

Honestly I just feel like the authors of these tools were just too lazy to
learn grep/find/cut/tr/bash/awk/etc and decided to implement everything in
their own toy program, which always

The list of "features" in the article lead me to the same conclusion

> no need of googling the right command

Yeah right but if you spent time learning the existing tools you would not
have to google it. And this new tool should require time to accomodate too.

> no need to look around for the right line in the output

I feel like the author just don't understand the unix philosophy. Instead of
having 1 tool with a quadrillion options, you just have to incrementally plug
and use all the available tools that are already part of linux distributions
since dozens of years. You don't need to "find the right line in the output",
you just grep/cut/awk the output, after some time it becomes second nature /
muscle memory.

~~~
jcelerier
> I feel like the author just don't understand the unix philosophy.

The unix philosophy isn't magically better and faster than other software
philosophies

~~~
Galanwe
Maybe, but has been used since dozen of years successfully and productively by
millions of programmers. It may be worth learning instead of reinventing...

~~~
addicted
Your complaint seems to be people are writing new tools.

You have provided absolutely no evidence that these tools don’t fit the Unix
philosophy (and you cannot, because the 2 tools mentioned actually do a great
job fitting the Unix philosophy). In fact, the first example is piping the
output of ls into fzf. I’m not sure what could be more Unix philosophy like
than that.

------
vbsteven
FZF is also very nice for Ctrl-r history search in the shell.

------
dmortin
May be of interest:

The author creates small wrappers to kill processes, search files, etc.

The concept could be extended to recognize certain object types. E.g. if you
select some files with search then you could choose from a list of operations
on files (delete, grep, copy path, etc.)

If you select from processes then after selection you could select from
process actions to perform on the selection (killing, sending some other
signal, etc.)

So this way you don't implement separate wrappers for every kind of usage, you
just create actions for certain object types and connect selections to object
types.

This is how Helm works in Emacs, and probably there is a VIM equivalent too.

------
throwaway8879
FZF/rg combination is so much snappier than Ctrl+P on my vim setup!

------
thameera
I use workflows in Alfred[0] for finding files, navigating to pages, and
searching around a multitude of other customized datasets. The advantage I
have with that over a fzf, at least for me, is being able to search instantly
with a Cmd+Space without having to switch to the terminal.

[0]
[https://www.alfredapp.com/workflows/](https://www.alfredapp.com/workflows/)

------
IronBacon
Using FZF to search the shell history is great until you don't find the
command you were searching, you need to abort and what you typed is canceled.
That's my only gripe with it.

I've tried to play with Zsh's Zle but wasn't able to find a way to abort FZF
and retain the input, I suppose I need to modify FZF itself.

If there's a way to do it with Zsh I'm all ears...

~~~
fluffything
In Helm you can go back and forth as much as you want. Sometimes you end up in
a dark alley, and you are just key press away from stepping back out and
trying somewhere else.

~~~
IronBacon
Emacs Helm? I'm so used to ido... ^__~

------
kazinator
> _It performs amazing even in a larger code base._

Doubt ripgrep it will beat indexing, line GNU id-utils. (mkid to build ID
file, lid to query).

If you're using git, "git grep" is useful; it searches only files indexed in
git, which provides a useful speedup.

~~~
burntsushi
> Doubt ripgrep it will beat indexing, line GNU id-utils. (mkid to build ID
> file, lid to query).

Does it provide the same user experience? i.e., Does it keep the index up to
date for you automatically? If so, that's something a lot of users aren't
willing to pay for.

If you want a pre-indexed solution, I'd recommend checking out qgrep instead:
[https://zeux.io/2019/04/20/qgrep-
internals/](https://zeux.io/2019/04/20/qgrep-internals/)

> If you're using git, "git grep" is useful; it searches only files indexed in
> git, which provides a useful speedup.

Depends on what you're searching. In a checkout of the Linux kernel:

    
    
        $ time LC_ALL=C git grep -E '[A-Z]+_SUSPEND' | wc -l
        3707
    
        real    1.033
        user    5.769
        sys     0.592
        maxmem  63 MB
        faults  0
    
        real    1.033
        user    0.000
        sys     0.008
        maxmem  9 MB
        faults  0
    
        $ time LC_ALL=en_US.UTF-8 git grep -E '[A-Z]+_SUSPEND' | wc -l
        3707
    
        real    3.624
        user    21.910
        sys     0.404
        maxmem  64 MB
        faults  0
    
        real    3.623
        user    0.000
        sys     0.008
        maxmem  9 MB
        faults  0
    
        $ time rg '[A-Z]+_SUSPEND' | wc -l
        3707
    
        real    0.138
        user    0.767
        sys     0.704
        maxmem  21 MB
        faults  0
    
        real    0.138
        user    0.003
        sys     0.006
        maxmem  9 MB
        faults  0
    

This is even despite the fact that `git grep` already has a file index
(ripgrep has to process the >200 `.gitignore` files in the Linux repo for
every search) _and_ the fact that `git grep` is also using parallelism.

------
dorfsmay
This looks interesting and I'm going to play with it, but if you still still
pipe PS into grep before killing, 'pkill -f' will do exactly what you want 80%
of the time.

~~~
pbhjpbhj
pgrep is pretty handy too.

------
digianarchist
There are a bunch of similar tools. I use
[https://github.com/peco/peco](https://github.com/peco/peco)

------
CoolGuySteve
How does ripgrep compare to silversearcher-ag for performance?

~~~
burntsushi
I did an extensive comparison a while ago:
[https://blog.burntsushi.net/ripgrep/](https://blog.burntsushi.net/ripgrep/)
\--- It should still largely be pretty accurate (and ripgrep has only gotten
faster).

More generally, if someone can find a non-trivial example of ag being faster
then ripgrep, then I'd love to have a bug report. (Where non-trivial probably
means something like "not I/O bound" and "not so short that the differences
are human imperceptible noise.")

~~~
elsamuko
I'm currently working on a searcher on my own:
[https://github.com/elsamuko/fsrc](https://github.com/elsamuko/fsrc)

When I started, I didn't know ripgrep, now I use it as reference. Of course
it's still slower for regex searches and it has less options, but in some
cases (e.g. simple string matching search), it is faster than rg (PM_RESUME in
160-170ms), mostly thanks to mischasan's fast strstr:
[https://mischasan.wordpress.com/2011/07/16/convergence-
sse2-...](https://mischasan.wordpress.com/2011/07/16/convergence-sse2-and-
strstr/)

If you want, let me know, what you think about it.

~~~
burntsushi
I don't see any build instructions, so I don't know how to try it. Sorry. I
did run `./scripts/build_boost.sh`, but that didn't produce any `fsrc` binary
that I could use.

I would also caution you to make sure you're benchmarking equivalent
workloads.

~~~
elsamuko
There are no build instructions yet, you need to build boost with
build_boost.sh and then open qmake/fsrc.pro with Qt Creator. There are
binaries available here, too:
[https://github.com/elsamuko/fsrc/releases](https://github.com/elsamuko/fsrc/releases)

And I know than benchmarking is hard, a coarse comparison is in
scripts/compare.sh. More detailed performance tests are in
test/TestPerformance.

~~~
burntsushi
I don't know what Qt Creator is. Please provide tools to build your code from
the command line.

I did some playing around with your binary, but it's pretty hard to benchmark
because I don't know what your tool is doing with respect to .gitignore,
hidden files and binary files. Your output format is also non-standard and
doesn't revert to a line-by-line format when piped into another tool, so it's
exceptionally difficult to determine whether the match counts are correct.
Either way, I don't see any evidence that fsrc is faster. That you're using a
fast SIMD algorithm is somewhat irrelevant; ripgrep uses SIMD too.

On my copy of the Linux checkout (note the `-u` flags passed to ripgrep):

    
    
        $ time /tmp/fsrc PM_RESUME | wc -l
        41
    
        real    0.143
        user    0.330
        sys     0.474
        maxmem  67 MB
        faults  0
    
        $ time rg -uuu PM_RESUME | wc -l
        17
    
        real    0.149
        user    0.564
        sys     0.690
        maxmem  13 MB
        faults  0
    
        $ time rg -uu PM_RESUME | wc -l
        17
    
        real    0.112
        user    0.481
        sys     0.675
        maxmem  13 MB
        faults  0
    
        $ time rg -u PM_RESUME | wc -l
        17
    
        real    0.118
        user    0.507
        sys     0.701
        maxmem  13 MB
        faults  0
    
        $ time rg PM_RESUME | wc -l
        17
    
        real    0.142
        user    0.749
        sys     0.726
        maxmem  21 MB
        faults  0
    

I originally tried to run `fsrc` on a single file (in order to better control
the benchmark), but I got an error:

    
    
        $ time /tmp/fsrc 'Sherlock Holmes' /data/benchsuite/subtitles/2018/OpenSubtitles2018.raw.sample.en
        Error  : option '--term' cannot be specified more than once
        Usage  : fsrc [options] term
        Options:
          -h [ --help ]         Help
          -d [ --dir ] arg      Search folder
          -i [ --ignore-case ]  Case insensitive search
          -r [ --regex ]        Regex search (slower)
          --no-git              Disable search with 'git ls-files'
          --no-colors           Disable colorized output
          -q [ --quiet ]        only print status
    
    
        Build : v0.9 from Jul  5 2019
        Web   : https://github.com/elsamuko/fsrc
    
        real    0.005
        user    0.002
        sys     0.002
        maxmem  9 MB
        faults  0

~~~
elsamuko
I included qmake and added a `deploy.sh` in the main source folder, which
generates the deployed zip file. Let me know, if this doesn't build.

    
    
      * gitignore behaviour: If there is a .git folder in the search folder, it uses git ls-files to get all files to search in
      * a .git folder itself is never searched
      * hidden folders and files are searched
      * binaries are ['detected'](https://github.com/elsamuko/fsrc/blob/f1e29a3e24e5dbe87908c4ca84775116f39f8cfe/src/utils.cpp#L93), if they contain two binary 0's within the first 100 bytes or are PDF or PostScript files.
      * pipe behaviour is not implemented yet
      * it supports only one option-less argument as search term
      * folders are set with -d

------
liangzan
Emacs has something similar to FZF called ido or ivy

------
agumonkey
Can this be hooked in <shell> kinda like pagers ? so ever long listing gets
piped automatically to fzf ?

~~~
OJFord
Yes. The composability (in usual Unix way) is the best thing about fzf.

I use it for a slew of git subcommands for example, e.g. if they expect a ref
and I don't provide one, open log and fzf a SHA.

I also use it in vim to find files or lines within them.

I also use it with my password manager to find the one I want if what I
specify isn't an exact match.

fzf is great.

------
TheGrassyKnoll
See also pgrep & pkill

------
leshow
ripgrep is great, all of the cli options are very memorable and it has sane
defaults for everything that I want to use it for. The one thing I add to a
ripgreprc is --smart-case

------
surfsvammel
I’m getting one

------
archy_
I see these Vim-enhancment posts a lot. If you need to install a mountain of
plugins just to make it usable, why not use a more modern editor? Seems like
nostalgia for the Unix greybeard era, possibly some eletism for when someone
who isn't intimately familiar with their config has to ask for help to use
their machine.

~~~
ladberg
Exactly. I use a modern editor whenever I'm working on one of my main
computers, and the only time I use vim is when I'm working on a remote server
and can't mount the drive remotely (or where mounting would just be a pain).
Because of that, I don't want any plugins when I use vim as I'll probably be
using it on a new machine every time, and setting up my environment would be a
waste of time.

~~~
PerryCox
Setting up your vim environment is as cloning a git repository that contains
your .vim files. Takes me about ~60 seconds to have vim up and running with
all my favorite plugins. That's faster than you can download and install any
other text editor. It's what I've been doing on just about every machine I've
used for the past 5 years.

There are situations where git is not installed or I can't download those
files for security reasons set by administrators, but those situations have
been pretty rare for me.

