My primary use-case for command line is very simple. Most of the time, I just go to a specific directory, and build/run something there. Rarely, I open up a finder window, and even more rarely I might open a file in my editor.

The straight forward way to do such things is to first cd to the directory you want. Anyone who has ever worked with Java/Scala projects knows how deeply nested the sub directories could be, so naturally I was looking for a better solution. A while back, I stumbled upon autojump, which is kind of a Google’s /I’m feeling lucky/ feature for cd. It works great, as long as the top ranked entry is what you want. However, sometimes I wish I had more control over the result, specifically I wanted a better way to interactively filter the ranked list.

Thankfully, I found FZF, a superb command line fuzzy finder which helped me solve this problem (it is worthwhile installing FZF even if you don’t want to read the rest of this post. It is that good.). What I did was to simply combine FZF and FASD (FASD is a bit more flexible tool compared to autojump). The rest of this post assumes that you have both of them installed. In OSX, you can use brew to achieve this:

brew install fasd fzf

Once installed, ensure that the necessary init commands are placed in your shell rc. I use zsh, so I put them in my .zshrc. The next step is to create a command that will combine these two and act as a replacement for the cd command. For instance, if you use zsh, you can do:

unalias j 2>/dev/null
j() {
    [ $# -gt 0 ] && fasd_cd -d "$*" && return
    local dir
    dir="$(fasd -Rdl "$1" | fzf -1 -0 --no-sort +m)" && cd "${dir}" || return 1
}

What this function does is to define the shell command j. When you use j with an argument (e.g., j e), it simply passes the argument to fasd which will take you to the first result based on the keyword (in my case, the top hit for e is my .emacs.d directory). If I don’t use an argument to j, the function takes the ranked list from fasd and feeds it to fzf, letting you fuzzy search on the list!

Note that this is not limited to just the cd command. For example, I have defined command e that uses $EDITOR to open a file:

unalias e 2>/dev/null
e() {
    [ $# -gt 0 ] && fasd -f -e ${EDITOR} "$*" && return
    local file
    file="$(fasd -Rfl "$1" | fzf -1 -0 --no-sort +m)" && ${EDITOR} "${file}" || return 1
}

All these functions (and more) are defined in my .zshrc, which can be found here.