optimizing your workflow with fzf & ripgrep
Tags: bash, vim, productivity, webdev
Published: 2020-05-23 02:29:18

On the back of my [post about my favourite vim plugins](https://dev.to/haydenrou/the-only-5-vim-plugins-i-need-4b7h), one tool that sparked particularly more interest was file and keyword searching using fzf & ripgrep. For that, I decided I'd give my 2 pence on what features I use the most and how I have them integrated into my workflow.

Let's start with how you can use it outside of vim

# the terminal
### fzf
{% github https://github.com/junegunn/fzf no-readme %}

Whether you use [bash](https://en.wikipedia.org/wiki/Bash_%28Unix_shell%29), [zsh](http://www.zsh.org/) or [fish](https://github.com/fish-shell/fish-shell), fzf works great with an easy installation process. Just follow along from their [github page instructions](https://github.com/junegunn/fzf#installation).

As I'll keep saying, one of the main benefits of using fzf is the speed - it's just incredibly fast. But let's look at the use-cases and see exactly how it can speed up your workflow.

#### command line search
Whatever code editor you use, you most likely have a file searcher, usually bound to `ctrl-t` or `ctrl-p`. In vim, a lot of people use [ctrlp.vim](https://github.com/kien/ctrlp.vim). 
Fzf has this built into the command line, and it's super fast if I didn't already mention.

Simply press `ctrl-t` and your files will be loaded, you can use a fuzzy search and look for whatever you need. (fzf will by default ignore what your `.gitignore` file contains)
You may ask, what use is this if it just pastes the file to the command line? Well - take it to the next level and pipe (`|`) it into a command.

Working on several different features at once in a big application, and forget branch names?

`git branch | fzf | xargs git checkout`

![fzf to git](https://dev-to-uploads.s3.amazonaws.com/i/npw4p787dchjf8yn2tpw.png)

I personally alias this in my `bashrc` as the following, which makes my branch swaps easy as pie: `alias gcob='git branch | fzf | xargs git checkout'`

#### command history
This is probably the best feature here. How many times have you typed part of a command and hit `ctrl-r` until you reached the right one, only to realise you got part of it wrong and have to `history | grep my_command` to figure out what you ran. Not no more.

Fzf has built in `ctrl-r` functionality which when you find your command and press return will paste it to your command line, allowing you to edit it before sending it off.

I can't begin to tell you how useful this is.

![fzf backward search](https://dev-to-uploads.s3.amazonaws.com/i/5nb6drq856giuts0lcl2.png)

### autocomplete
When searching for a file to edit or a directory to move to you can simply `**<tab>` to use fzf and complete your command.

![star search fzf](https://dev-to-uploads.s3.amazonaws.com/i/vso5cbdj4e9hfyj3vyme.png)

Take it to the next level with ssh support - `ssh **<tab>`. Awesome right?

### patterns
Fzf also has patterns. Want to find a file that specifically ends in `.rb`? Just add `$` to the end of the search. Omit specific searches? `!ignored_search_result`

## ripgrep
{% github https://github.com/BurntSushi/ripgrep no-readme %}

You've probably guessed by now that I _love_ fast programs. Ripgrep is no exception to the rule. Another tool that outright shows their speed in their readme, it really lives up to it.

You can plug it in to fzf with the following, or use it for simple greps as per below.

`export FZF_DEFAULT_COMMAND="rg --files --hidden --follow --glob '!.git'"`

On the command line you can use ripgrep as simple as `rg 'my_search'` and it will recursively find your results in a flash. And it comes with some great options; `--hidden` to show hidden files; `-s` for case sensitive searches; `-l` to just show the files that contain the result without showing the context; and `-g` to include or exclude files or filetypes, such as `rg 'my_string' -g '*.rb'`.

But the real fun comes in when you use it in vim.

# vim
Both fzf and rg work extremely well with vim. To get started, you'll have to get a couple plugins for fzf.

```
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
Plug 'junegunn/fzf.vim'
```

And ripgrep works great with a small command to plug it in.

`set grepprg=rg\ --vimgrep\ --smart-case\ --hidden\ --follow`

I personally don't use `set autochdir` ([auto set current directory](https://vim.fandom.com/wiki/Set_working_directory_to_the_current_file)) so setting the below will use the current working directory (`cwd`) for ripgrep.

`let g:rg_derive_root='true'`

Here are another few configurations I use with fzf & rg in vim. This is personal preference so go ahead and use work makes the most sense to you.

```
nnoremap \ :Rg<CR>
nnoremap <C-T> :Files<cr>
nnoremap <Leader>b :Buffers<cr>
nnoremap <Leader>s :BLines<cr>
```

#### :Files is not working
Check out [this github issue](https://github.com/junegunn/fzf.vim/issues/456) if you're having this error. I made the below simple fix in my vimrc and haven't had any problems since.
```
set rtp+=~/.fzf
set rtp+=/usr/local/opt/fzf
```

Now the magic happens.

#### searching
For those of you familiar with vim mappings, you've probably already guessed, but simply press `ctrl-t` to open up the menu, and get searching!

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ioyghu2mvb5x5mfq5gxn.png)

As you've probably noticed, this gives you a brilliant preview screen for the file you're planning on opening up. I find this brilliant with no performance change, however if you prefer no preview window, just use `:FZF` instead of `:Files`.

From inside the menu, fzf will automatically detect `ctrl-t` to open the file in a new tab, `ctrl-v` for a vertical split or `ctrl-x` for a horizontal split.

#### buffers
I bind `<leader>b` for my buffer menu, opening the standard fzf menu for all files in my buffer. This is super useful if you've had a long vim session going.

`:BLines` will simply search the current buffer for a specific string. You may be thinking you can do this with vims `/` or `?` - but sometimes it's nice to see all occurrences in one window and look through, instead of spamming `n` or `N`. If you want to look at all the current buffers, you can use `:Lines`.

#### multiple files
One other cool feature from the fzf menu that I mainly use in vim is `<tab>`. As you can see below, I've selected several different files and now I can go through them one at a time to see or make the changes I needed.

#### rg
This plays well with `rg`. My `\` binding will open a menu and scan all files recursively from your current working directory. Search for the string you want, and use fzf as you would normally.

![rg search](https://dev-to-uploads.s3.amazonaws.com/i/g375dvqj3nsge51jb6x2.png)

# Bonus - Search & Replace
Whilst we're at it, lets go over a couple ways to find and replace in vim using fzf/rg.

If you search using the above set mapping `\` for a keyword you need, and press `<tab>` on the files you want to change, vim will then open up a Quickfix list. Inside of here, you can simply `:cfdo %s/my_search/replacement/gc` to go over all the changes. You can then `:cdo update` or `:wqa` to update them all - easy!

If you'd rather do this through the command line, `rg` and `sed` make this super easy.
`rg -l 'my_search' | xargs sed -i 's/my_search/my_new_value/'`
and you're done!

If you're using OSX - you may want to note an oddity with `sed` addressed [here](https://stackoverflow.com/questions/19456518/invalid-command-code-despite-escaping-periods-using-sed) which you can fix by simply changing the command to
`rg -l 'my_search' | xargs sed -i '' -e 's/my_search/my_new_value/'`

# Conclusion
Searching files and their contents is something that any text editor worth using must accommodate. Fzf & Ripgrep makes vim not only accommodate it, but thrive with them. Why settle for anything less?

As always, here are my dotfiles, configuration for vim and other config files. Feel free to check them out!

{% github https://github.com/haydenrou/dotfiles no-readme %}

Cheers :)