Favorite Apps & Tools #4 - fzf

What is fzf

Again starting with quotes by the developer, Junegunn Choi.

fzf is a general-purpose command-line fuzzy finder.

It’s an interactive Unix filter for command-line that can be used with any list; files, command history, processes, hostnames, bookmarks, git commits, etc.

However with this one, I will take a shot at explaining some aspects together with some examples.

fzf takes in a list of stuff through the stdin, gives you an interface to fuzzy match (a) line(s) and spits out the result(s) to the stdout. The delimiter for the list should be a new line \n.

A fantastic example of a tool that does one thing brilliantly. Unix philosophy and all.

This does not sound like much at first, but with the tool being on the command-line one can imagine what one can do with it in a pipeline.

fzf has of course a few options to make it even more appealing. File preview, multi selector and sorting to name a few.

Few Examples of mine

For illustration purposes these are some examples that I use myself.

My gitlab dotfiles repository should have more of the stuff that I use fzf for if you like to go fishing there.

Now if you want to get even more inspiration. There are a whole bunch of community examples in the git repository of the author.

Find & open files

This finds files with fd, pipes the list into fzf and the fuzzy matched results get opened with Vim. It also uses bat for file previews.

function fv() (
    export FZF_DEFAULT_COMMAND="fd -p -i -H -L -t f -t l -t x \
-E 'icloud/*' \
-E 'Library/*' \
-E 'Pictures/Photos Library.photoslibrary/*' \
-E '.git'"
    IFS=$'\n' \
       files=($(fzf --reverse \
                    --preview "bat --theme=timu-spacegrey --color=always {}" \
                    --query="$1" --multi --select-1 --exit-0))
    [[ -n "$files" ]] && vim "${files[@]}"
)

Change directory

This uses fzf, fd and cd in the pipeline.

function fcd() {
    export FZF_DEFAULT_COMMAND="fd -p -i -H -L -t d \
-E 'icloud/*' \
-E 'Library/*' \
-E 'Pictures/Photos Library.photoslibrary/*' \
-E '.git'"
    local dir
    dir=$(cd && fzf --reverse +m) && cd && cd "$dir"
}

Find & install Homebrew cask

This one is fairly wonky but quite self-explanatory.

function bcinst() {
    curl -s https://formulae.brew.sh/cask/ | \
    grep '<td>' | \
    grep href | \
    awk -F '/' '{print $3}' | \
    awk -F '"' '{print $1}' | \
    fzf -m | \
    xargs brew install --cask
}

Switch folders in neomutt

I use NeoMutt as a fallback from Mu4e in Emacs for my emails. But I have gotten so used to the fuzzy matching interface in Emacs (ivy) to jump to emails folders that I need it here as well. fzf to the rescue:

match_folder() {
    find $HOME/.maildir -name '*' -type d \
         -mindepth 2 -maxdepth 2 |\
        grep -v '.git' | grep -v '\/mu' |\
        fzf --reverse
}

folder=$(match_folder)

echo "push 'c$folder<enter>'"

Ranger integration

Admittedly and exactly because of the awesomeness of fzf I don’t use ranger as a file manager anymore. But while tinkering, I managed to integrate fzf in ranger as a command.

class fzfcd(Command):
    def execute(self):
        command = "cd && fd -p -i -H -L -t d \
-E 'icloud/*' \
-E 'Library/*' \
-E 'Pictures/Photos Library.photoslibrary/*' \
--no-ignore-vcs --exclude '.git' | fzf"
        fzf = self.fm.execute_command(command, stdout=PIPE)
        stdout, stderr = fzf.communicate()
        directory = stdout.decode('utf-8').rstrip('\n')
        directory = os.path.join(os.environ['HOME'], directory)
        self.fm.cd(directory)

Fzf in Vim

The author of fzf created fzf.vim as well. An awesome plugin for Vim that implements great fuzzy matching for a whole host of commands.

:Files [PATH]
Fuzzy match and switch to files.
:GFiles
Fuzzy match and switch to files in a git repository.
:Buffers
Fuzzy match and switch to buffer.
:Ag or :Rg [PATTERN]
Fuzzy match and switch to search results with The Silver Searcher, ag or ripgrep, rg.

This are just a few of the available commands. :h Files in Vim will get you to the help section with an exhaustive list.

Conclusion

There is an argument to be made that fuzzy finding/matching is the best user interface out there. Not just for the CLI, but for any kind of navigation, period.

This is somewhat evident by the popularity of such programs as Alfred in macOS, completion frameworks in Emacs (vertico, ivy, helm, etc.), rofi & dmenu for Gnu/Linux users and vast number of other tools, utilities and applications.

As I believe to have shown here with just the few examples, fzf masters the fuzzy matching/finding on the command-line like a champ. Enough said!