I use fzf in this very way and could have written this article if I weren’t lazy lol. However, I can add two other use cases:
1. I use i3wm at home (haven’t yet made the jump into Sway/Wayland), and don’t want to change my screen resolution by opening an app, clicking with my mouse, and then waiting. So I use fzf for quick resolution changes using xrandr:
2. At work I switch between multiple Kubernetes contexts during the day. To make the switch fast without typing a sentence, I will use this helper function:
I found this to be better than tab-completion because with tab completion I only get the name of the context, and not the cluster/user/namespace fields that make it easier to select the right one.
Use the above at your own risk, as they are fast hack-ups and could be far more clear (my sed skills are prone to error and overly verbose).
I would highly recommend looking at something like kubectx [0] to manage switching between kubernetes contexts! I've been using this for a while now and have it aliased to kx. It supports tab completion, as well as fzf integration if you have it installed [1]. There's also kubens in there which does the same for namespaces!
Just a heads up that the quotes used in the kc function appear to be "smart quotes" and will likely throw an error if copied verbatim into your shell config
Those are very creative use cases for fzf, I had never considered doing something like that.
My usage of it probably counts as quite basic. That said, I use it constantly. I just love the feeling of real time interaction it gives - it is well and truly part of my muscle memory now.
I use the vim plugin too, which is also brilliant and makes navigating larger projects very quick and easy. I use these two extra bindings all the time:
Yeah, the ability to fake a "show all references to this identifier" via integrated ':Rg' is the greatest feature of FZF I've encountered yet, and makes for a passable substitute of one language-server must-haves.
Hey, sorry that I didn't really try to explain the bindings. Climb_stealth said it all really but here are some extra bits.
The first one is a normal mode binding (the n in nnoremap). yiw copies the word you are currently on (without surrounding spaces), and then <C-r>" pastes that into the :Rg command. The :Rg command is part of the fzf vim plugin and it is a wrapper around ripgrep (see the link from climb_stealth), which gives you fuzzy search over the results of a ripgrep search.
It's basically just how you paste the contents of registers into commands.
The second one is almost exactly the same except that it is a visual mode mapping (the v in vnoremap). If you highlight something with visual mode, then use that command, it will search for the highlighted text using ripgrep.
<C-Space> is just the key chord that the command is bound to. It is a pretty arbitrary personal choice, I find it a very quick and easy chord combination but you can put whatever you want in there. For example, <C-S> would activate the command when you pressed the chord 'control + s'.
There is quite a good list of keys that are unused by vim here:
'yiw' is yank inner word. It basically copies the current word from wherever you are in that word. The pure yank 'y' I presume would just work if you already have something highlighted. It looks like these shortcuts take the current word or current selection and pass it to Rg [0] to be searched for.
I don't have the plugin but it sounds super useful and I'm going to give them a try.
Junegunn, the fzf author, makes great vim plugins too. Both the user experience and the developer experience (the code of these plugins) feel just right.
Fzf is better integrated in vim than in emacs. So I use dmenu on X/wofi on wayland instead, which are basically GUI fzf replacement.
Both fzf and dmenu are "selector menu" utilities, in turn, for terminal and X, but for dmenu, fuzzy search is not its main thing. It has a fuzzy patch though...
I love fzf and tend to use it whenever repeatitive, non-static behavior is in play.
Replacing Ctrl-R with fzf is the most basic and most useful usage.
Basically every git command involving history, branches etc have fzf wrappers in my setup.
My latest, least common usage is having built a wrapper around KeepassX and keepassx-cli to access my secrets from the CLI with fzf to fuzzy search entries. Saves me a lot of time every day.
I mostly use it to open files in vim [0]. The good thing about these aliases is that they keep the command in the shell history. So you open a file with the alias and it will leave a full 'vim path-to-file' in the history.
# Open any file under current dir
vf() {
files="$(fzf --query="$1" --multi --select-1 --exit-0)"
if test -n "$files"; then
echo "${EDITOR:-vim} \"$files\""
print -s "${EDITOR:-vim} \"$files\""
${EDITOR:-vim} "$files"
fi
}
# Open from current modified files in git repository
vfc() {
files="$(git ls-files -m | fzf --multi --select-1 --exit-0)"
if test -n "$files"; then
echo "${EDITOR:-vim} \"$files\""
print -s "${EDITOR:-vim} \"$files\""
${EDITOR:-vim} "$files"
fi
}
I also have a "create feature branch from JIRA issue" (it was in the list of ideas in this post I wrote for the engineering blog at work [1] about autocompleting EC2 instances, although I was already using it). The JIRA API is a bit too slow for fast response, so what I do is populate a text file via a cron job that requests from the API regularly, and use the text in the file for the completion.
Forgot to add that at some point I had a similar autocompleter to the one in the blog above, that would connect to N chosen machines (using the _multiple_ fzf setting), pane them in a tmux session automatically and thus allow you to send the same command to all of them. I only used it twice, but was kind of fun to write.
If anyone is interested in a rust version (probably the main benefit being you can use it as a rust library) there is a similar tool called skim[1]
It's actively developed and seems to have a non-overlapping set of features with fzf other than the basics (they both have features the other doesn't, and skim copies most of the core ui from fzf)
Last I heard, skim's fuzzy search was not "as good as" fzf (I don't know in what measure?)...
And there were talks of how skim could not utilize concurrency as efficiently as fzf and that has something to do with how Rust handles concurrency and how Go does it...
These were just the result of me skimming (ha!) over internet posts so I'd be curious if anyone could elaborate on them...
When I tried skim the list didn't update as "smoothly" as fzf, in response to changing input. No language bias here! (I personally use Rust but not Go) I'd be interested to know more.
Fzf can be a tremendous time-sink because its credible promise to improve your quality of life in the terminal.
One of my most-frequently-used pry customizations is a keybinding that opens the current backtrace in fzf, with the preview window showing the selected location, allowing me to quickly walk up or down the stack, with tons of context. `enter` takes me to that frame, and `ctrl-v` opens that file location in vim.
The vim integration piece uses the same concepts as the gdb integration. The rest uses some (very ugly) local scripts, cobbled together in 10-minute snatches of time over years. Hopefully, the functionality of the pieces not included here can be inferred from the names.
Fzf is great, but unfortunately it doesn't have line wrap (there's an open bug basically marked as WONTFIX). So if you frequently work with long commands and want to use fzf to search for older commands with Ctrl-R, things will be quite complicated :-(
There's an easy workaround. I use a keybinding such that when searching through commands with Ctrl-R I can press ? to display the the full wrapped command in a preview window at the bottom of the screen.
You're misreading what I'm saying, it's the other way around. fzf doesn't support line wrapping very long lines.
I have really long commands in my shell history and fzf just truncates them, which makes it pretty useless in many cases, since those commands are similar or identical up to 80-100-120 characters.
So in many situations I kind of have to guess which command has the parameter that I want at the end.
It's not that my shell history has lines with line wrap in them, it's that fzf can't show long commands on multiple lines so that I can see the entire command...
As a hack, you could do pre process to hide some of the common prefix, pass it into FZF, and then post process to add back the prefix, before finally running it.
Basically, something like:
history | strip-prefix | fzf | add-prefix | bash
I'm not sure if it would be useful, but I think it's worth a try (and would be a fun project).
I think the first example should have been done with direnv rather than having a manual step, but I supposed to each their own. The other examples are all pretty neat.
I recently set up fasd, which I recommend, but I tied it together with fzf, which makes it really nice.
My only constant usage pattern for this is integration with 10000 last unique lines of Redis stored history across all the systems I use. Push every unique command into a single Redis across all the systems, Ctrl-R to pull it via fzf. It really improves command line performance.
I use bash. I'm sure zsh has something similar as hooks.
This is my setup.
PROMPT_COMMAND variable is set to a function that "history 1", pulling the last command entered. That command is piped into a command line tool that pushes a single line into a Redis list. The list is trimmed to no more than 10000 entries.
Ctrl-R is bound to a function that uses a tool to connect to Redis, fetches the list, finds uniques, and pushes them as the input to fzf. The selected command becomes a shell variable BUFFER. Finally, READLINE_LINE=${BUFFER} and READLINE_POINT=${#READLINE_LINE}, thus inserting the ${BUFFER} into the command line and moving the cursor to the end of it.
This allows me to edit the pulled command.
All systems/vms point to the same redis running on a server and using the same list key, thus allowing for a shared command line history. If the server is unreachable, the hooked functions use shell's history instead of the redis server to fetch last set commands( fewer lines, obviously ). In additional to that failure to connect to redis server switches makes the shell prompt two lines where the first line says '[Command history server unreachable/shell server cli tools not found]' and the second line becomes a standard prompt.
I have been running this for 2 years with zero issues. Initially I thought doing connect->push->disconnect will be too slow, but I'm not noticing it much, even over the Wifi. I've been thinking of converting this service into a container to add an archive of when, where and what was typed in addition to the current setup.
After fiddling with Emacs, I have a persistent thought that the shell would benefit considerably from more featureful completion in the style of Helm/Ivy, instead of just a list with an occasional ‘preview’. The shell is a programming environment, after all, with all the commands and executables being the library—so we need to finally treat it as such.
For starters, I want the completion to show the arguments order for a command, and one-line description for each option. Perhaps my completion config is just incomplete, but somehow I haven't seen any howtos of this scale yet.
As the shell developer cannot know in advance which commands and programs you'll use, it becomes a problem of providing a good way for developers to provide the shell a way to inspect and complete.
Bash has a very good way of doing that. Actually Debian based distributions have very good completion scripts.
git, apt and other very used programs have good completion.
Figure I'd link my git aliases here, that make heavy use of fzf. The goal is generally to never have to type a filename (eg. for git add) or a commit hash (eg. for cherry-pick).
Here's a link to my 'cp' alias that lets me choose a branch, then a commit to cherry pick into my current branch:
I have to read through yours which indeed look nice from a quick scan, but if your goal is firstly to save typing file paths, I presume you instead considered just having a shell mapping to do that instead of needing to instrument aliases for each command? Here's mine, which I get by hitting ctrl-s anywhere in any command line: https://github.com/Julian/dotfiles/blob/main/.config/zsh/com...
You can get similar behavior out of the box with fzf by typing `git add **[tab]`. The difference with what I do in my aliases is that I take the choices of files to add from the output of git status.
I have, after some extreme madness, slightly adapted (and I dare say improved) the github checkout one. My use case is to check out PRs that have had my review requested, so I changed the JQ command to do that (which you may or may not want), but the real masterstroke was adding in previewing the body of the PR with mdv. Key to doing that was switching to null delimited lines.
I did my damnedest to use the unit separator character 0x1F instead of tab in between fields but I could not figure out how to get FZF to like it. It makes me so sad that those characters with absolutely primo spots in the ASCII table and that ACTUALLY MEAN what we use tabs (or commas, or pipes) and linebreaks for don't get any love. Ah well.
I saw this tool to find pytest cases after I implemented my own simple fzf shell function that uses bat for preview.
https://github.com/dbaty/testfinder
I also implemented simple bash functions to:
+ Select a CMake target to build
Extract all add_executables defined in the CMakeLists of my project directory and pipe the fzf selection to cmake to build
+ Find and sort (by mtime) all compiled executables placed in the cmake build directory
It can be hard to remember the path of the executable produced by cmake, so i find all executable files in the cmake build dir, ls -alh, sort them by mtime (you want to execute the most recently compiled binary) and pipe to fzf
Any time I pipe something to grep, I think if this could become an fzf-based command. Highly recommend people do the same with their workflows.
Nice, I love fzf! It’s an amazing recursive search replacement, but my favorite use was a script I wrote for changing git branches, where they were sorted by most recently changed so that the branch you’re probably looking for is only a few lines away, but you can go back pretty far too if you want. It feels like tig but for changing branches, it’s awesome.
Some excellent scripts, I like the one with `--multi` to delete git branches.
My most powerful bash alias has become this one [1], where `subl` is the editor of my choice. I no longer search files, I find them. Really, fzf is almost indistinguishable from magic and has become crucial to my workflow.
This is great. I created something vaguely similar a while back, but probably does not allow for as much complexity. https://github.com/seiferteric/clamp
1. I use i3wm at home (haven’t yet made the jump into Sway/Wayland), and don’t want to change my screen resolution by opening an app, clicking with my mouse, and then waiting. So I use fzf for quick resolution changes using xrandr:
2. At work I switch between multiple Kubernetes contexts during the day. To make the switch fast without typing a sentence, I will use this helper function: I found this to be better than tab-completion because with tab completion I only get the name of the context, and not the cluster/user/namespace fields that make it easier to select the right one.Use the above at your own risk, as they are fast hack-ups and could be far more clear (my sed skills are prone to error and overly verbose).
—Edited for HN formatting