Using FZF instead of DMENU
Be it dmenu, spotlight, synapse or any other launcher that allows you to lazily write a few letters and then finding the program that you actually meant -once you are used to those neat little buggers you won’t want to go back. Ever!
TL;DR
This is a quick summary on how to replace dmenu with fzf as your fuzzy launcher. While dmenu is fast and pleasant I find the fzf fuzzy finding algorithm more powerful and convenient.
I am using bspwm as my window manager, but there is nothing specific to bspwm except for the one rule that will let the launcher float centered. You should be able to use fzf in dwm, i3 or some other window manager without any problem.
My dotfiles should have everything you need to set it up on your own (but don’t worry, I will walk you through it).
The first part describes how to pipe commands into fzf and execute the filtered command afterwards.
The second part shows how to start a new terminal window to execute the fuzzy finding in.
The third part gives a few specifics on how to style and arrange the window via Xdefaults, bspc rules, fzf configuration and binding it to hotkeys via sxhkd.
Good news: fzf already did the hard work for us by being an amazing and very fast fuzzy finder!
You can use it as a normal unix filter and pipe anything you like into it:
ls | fzf
I first came across it as a vim plugin tho. There were previous attempts to include fuzzy finders into vim (ctrp_p and the like), but non of them came close to fzf (imo) regarding speed and having no dependencies.
Part 1, fzf
List of executables in path | fzf
First we need something to pipe into fzf, a list of executables that we want to filter through.
Easily done:
compgen -c | sort -u
Or if you do not want to rely on compgen:
echo -n "$PATH" | xargs -d: -I{} -r — find -L {} -maxdepth 1 -mindepth 1 -type f -executable -printf '%P\n' 2>/dev/null | sort -u
You can then pipe it into fzf. You know what, go ahead, do just that. You might not even need more than this, or want to proceed to your setup-specific configuration. You might want to at least continue through the next part though, it might save you some time.
$(executables | fzf)
Alright, next you want to execute whatever command you have filtered out. There is multiple ways of doing this, one could be command substitution:
$(compgen -c | fzf)
Ok, that works! However, try to launch something that takes a bit of time, say… firefox? As you can see, your terminal is blocked while firefox starts up. If at any time you send a SIGINT via Ctrl-C you will also quit firefox.
No problem, just background it!
$(compgen -c | fzf) &
Part 2, fzf and X
Starting it in a new terminal window
We want to start fzf in a new window to make it behave like a proper launcher. Here is an example of a wrapper script that does just that:
xdotool search --onlyvisible --classname URxvtFuzzy windowunmap \
|| xdotool search --classname URxvtFuzzy windowmap \
|| urxvtc -name URxvtFuzzy -geometry 40x8+297+1 -e sh -c 'compgen -c | sort -u | fzf | sh'
This is pretty neat, because it sort of acts as a window toggle, making sure that you don’t accidentally spawn tons of those windows.
Plus, by giving the window a name (CW_CLASS) you will be able to customize without affecting your other urxvt instances.
However: you will probably have a problem with this. The silly new window will not go away once you have started your program. If you kill this window you will kill the spawned child process too. Meh. Backgrounding also doesn’t work, it would background fzf, making it impossible to actually filter.
There are a few tricks you can do, but all of them have some caveat or another. To cut a long story short:
I wrote a tiny go program that launches a process and moves it out of the process group. It is called lnch. You can install it via go get github.com/oem/lnch
My final window launcher looks like this (I split it off into two wrapper scripts so that I can launch windows with other “fuzzy lists”:
#!/bin/sh
# fuzzy_win launches the script from param in a centered window
xdotool search --onlyvisible --classname URxvtFuzzy windowunmap \
|| xdotool search --classname URxvtFuzzy windowmap \
|| urxvtc -name URxvtFuzzy -geometry 40x8+297+1 -e $1
and the actual fuzzy filtering:
#!/bin/sh# fuzzy_cmd filters a command via fzf and launches it with lnch
# use it together with fuzzy_win like this: fuzzy_win fuzzy_cmdcompgen -c | sort -u |fzf | xargs lnch
Part 3, fzf and bspwm
some tweaks in fzf
fzf --color=bw --reverse --border
The above parameters will launch fzf in b/w, with borders top and bottom and having the prompt at the top. You can do a few more tweaks with fzf like color settings, check out man fzf for more details on this.
.Xdefaults
URxvtFuzzy*internalBorder: 30
Remember how we named the terminal window? You can customize this terminal as much as you want without affecting your other terminal windows!
bspwmrc
bspc rule -a \*:"URxvtFuzzy" state=floating center=on sticky=on
Yeah, that naming also allows us to declare some specific rules for our window, namely that it floats in the middle of our screen.
sxhkdrc
super + space
fuzzy_win fzf_cmd
That’s it! Or rather, that is just the beginning. Commands are not the only thing you can filter with fzf. How about your chrome history, bookmarks, wifi networks etc? It is so convenient that I am currently making this the centerpiece of my system “ui”. Anyways, you should check out the fzf examples if you haven’t already and need some inspiration.
github.com/oem/dotfiles (my dotfiles, including a lot of the code snippets from this post)
github.com/oem/lnch (lnch on github)