Simple Note-Taking with fzf and Vim
Improve your life with fuzzy finding
TL;DR: Install fzf (`brew install fzf`), then download this bash script for a nice little note-taking app.
I recently found fzf, a great utility for general-purpose fuzzy finding on the command line. I’ve been using it — along with Vim and a little bash script — as a fast, simple note-taking tool, and I wanted to share my setup.
Fuzzy Finding
I first learned about fuzzy file finding from Destroy All Software. Gary used the Command-T Vim plugin for file navigation, and it was kind of mind-blowing to see how fast he was able to switch between files. I was accustomed to laboriously typing out full file paths or clicking through directory trees in my editor, and finding out that I could instead simply type a hotkey and 4 or 5 letters changed how I approached navigating file trees.
The basic idea of fuzzy finding goes like this: given many possible choices, narrow down the options based on a user-entered string. Unlike traditional text search, the characters in the search string don’t have to appear contiguously in the result to count as a match — only in order. So, by searching for acurc
, app/controllers/user_registration_controller.rb
is found. The bolded letters are the ones that the fuzzy finder matched on.
fzf
In my daily life, I pretty much only use fuzzy finding for navigating files. That’s not all it can be used for, though, and fzf was built to generalize the idea. fzf is a command-line tool that accepts any input you want to throw at it, presents an interactive fuzzy-finder, then prints whatever you picked on stdout
. It has all kinds of options and customizations, and it is blazingly fast. It can handle very large input sets with no trouble at all.
Install fzf
If you’re on a Mac, it’s easy to install fzf:
brew install fzf
It is also available for Windows and Linux, as well as in non-Homebrew form on Mac; check the official docs if you need one of those.
fzf Basic Usage
If you run it without any arguments, fzf
will default to recursively finding all files in the current directory.
You can also pipe a list of things into it, for example the results from a big grep
search:
grep -r animal . | fzf
There are plenty of other possibilities, but those are the two main use cases: run standalone to search filenames, or pipe a list of stuff into it.
A Barebones Note-Taking App
The way I’ve been using fzf is as a lo-fi replacement for Notational Velocity (or, more accurately, as a lo-fi replacement for a hi-fi replacement for Notational Velocity, nvAlt). I keep a folder of Markdown files in Dropbox as my personal wiki. Everything goes in there, from dates and names I need to remember to cheat sheets for programming languages.
fzf accepts a --preview
argument which lets you provide a command to run against the currently selected result line. This lets us do something like this (I’ve also added some preview-window
options for cosmetic changes):
fzf --preview="cat {}" --preview-window=right:70%:wrap
and get this result:
So that’s a nice little interface over my notes folder. But I want to edit the notes, too, which is where the output from fzf comes in. Since pressing <enter>
exits fzf and sends the selected filename to stdout
, I can pass that to my editor to open.
vim `fzf --preview="cat {}" --preview-window=right:70%:wrap`
That’s better, but I’m used to notes apps that just stay open all day. I don’t want to retype the fzf
command after every edit. After thinking about it for a minute, I realized I could write a bash script that loops forever between these two states — fuzzy file selector and text editor — and here’s what I came up with:
fuz.sh
You can put this script in the root of your notes folder, or do what I did and place it in your PATH
so that it’s globally accessible. I also renamed it to just fuz
on my machine so it feels more like a normal Unix command.
And the whole thing looks like this:
But What About…
There’s already an fzf plugin for Vim as well as a Notational Velocity clone that does pretty much what I just showed, so why would I bother writing my own wrapper? The main reason is on line 9 of the script: by referencing $EDITOR
instead of vim
specifically, this supports whatever editor you’d like to use, which I think is a bit more UNIX-y than the plugin approach. Even if you’re a devoted Vim fan, fzf
only works in a terminal, so GVim users can’t make use of the existing plugins.
Conclusion
fzf is a really flexible tool, and I’m sure I’ll find other ways to fit it into my workflow in the future, but for now I’m happy with it just as a notes app. If you’re using fzf in some particularly clever way, I’d love to hear from you!