junegunn/fzf
Lore
A timeline of fzf's evolution, derived from git log, tag dates, and CHANGELOG.md.
Eras
The Ruby prototype (Oct 2013 – early 2015)
The very first commit on 2013-10-24 introduces fzf as a single-file Ruby script. Junegunn Choi wrote it as a personal tool for fuzzy-finding files inside Vim and at the shell. The early commits ("Don't have to be files", "Fix arrow key handling", "Fix ctrl-b and ctrl-f") are all small UI patches to that Ruby implementation. The README from this era markets fzf as "a command-line fuzzy finder written in Ruby" with a heavy Vim slant.
The Go rewrite (mid 2015)
In 2015 fzf was rewritten in Go. The motivation was distribution — shipping a single static binary instead of asking users to install a Ruby interpreter. The rewrite kept the same UX but unlocked huge performance gains (parallel matching using runtime.NumCPU()) and Windows support. The Ruby implementation was removed; what remains under test/ is the Ruby-based integration test harness, which is unrelated to the original prototype.
The matcher generation (2016 – 2018)
src/algo/algo.go documents this era in its top comment: FuzzyMatchV1 was the original "find first occurrence" algorithm; FuzzyMatchV2, modeled on Smith-Waterman, finds the optimal scoring match. V2 became the default and V1 was kept under --algo=v1 for users who prefer raw speed over best-match selection. The scoring scheme — bonuses for word starts, camelCase, path separators; gap penalties; first-character multiplier — was tuned in a series of iterative changes during this era.
The action language (2017 onward)
Originally fzf had a hard-coded set of key bindings. The introduction of --bind and the action+action+... chaining syntax turned fzf into a programmable TUI. The action set grew steadily — reload, change-preview, transform-query, transform-prompt, become, put, change-nth, change-with-nth, etc. — and now exceeds 200 entries in src/actiontype_string.go. The placeholder language ({}, {q}, {n}, {+f}, {fzf:query}) grew alongside.
Preview, popup, and HTTP control (2019 onward)
Three features defined this period:
- Preview window —
--previewand the placeholder substitution machinery insrc/terminal.goopened the door to building rich pickers (file viewers, git previews, kubectl describe, etc.). - Popup mode —
--tmux(src/tmux.go) and later--popupfor Zellij (src/zellij.go) wrap fzf in a floating terminal, implemented via therunProxyindirection insrc/proxy.go. --listen(added in 0.36) — an HTTP control plane insrc/server.gothat lets external programs send actions to a running fzf. Re-bind keys, change the preview, reload the list, all overPOST /with a JSON body.
The everything-as-action era (2022 – 2026)
Recent releases keep generalizing the binding model. Almost every visible piece of fzf state has a corresponding action: change-border-label, change-ghost, change-header-lines, change-multi, change-pointer, change-prompt, change-query, change-preview-window. Combined with transform-* actions that compute new state from a shell command, fzf has become a small UI toolkit rather than just a picker. Version 0.72.0 (the current master HEAD) adds --header-border=inline, dashed border style, and several change-footer / change-header redraw fixes — the same theme.
Longest-standing features
- Tab-separated output: items printed on accept have been newline-separated since 2013;
--print0has been the toggle since the Go rewrite. --filtermode: non-interactive filtering shipped with the original Ruby version and survived the Go rewrite essentially intact (src/core.gostill has a clearly delineated branch for it).--ansi: the ANSI escape-sequence-aware tokenizer has been around since 2014;src/ansi.gostill resembles its early form, just with more edge cases.fzf-tmux: thebin/fzf-tmuxwrapper predates the in-binary--tmuxpopup and continues to ship; some users prefer it because it doesn't require tmux 3.3+.
Deprecated features
- The Ruby implementation (2013–2015) was removed when the Go rewrite landed.
- Several legacy options (e.g. older spelling of
--cycle, original--toggle-sort) were renamed; seeCHANGELOG.mdfor breaking changes between 0.x releases. - Custom border tags that predated the unified
--stylepreset have been folded into--style=default|minimal|full.
Major rewrites
- Ruby → Go (2015): the central one. Replaced the entire codebase, kept the UX.
- Tcell vs light renderer split: the renderer abstraction in
src/tui/tui.gowas retrofitted so the fast custom renderer (light.go) could coexist withtcell.go, gated by a build tag. - Walker: the file system walker was migrated to
github.com/charlievieth/fastwalkfor parallel directory traversal;src/reader.goretains the symlink-loop guard added when this happened (see the comment about z: → / on WSL/MSYS). - Action engine consolidation: binding handling has been refactored several times to support transform-* actions, action chaining, and async commands without blocking the matcher.
Growth trajectory
- 2013 – 2015: solo project; ~1 contributor active.
- 2016 – 2019: contributor count grows to a long tail;
Junegunn Choiandjunegunn(same person, different commit identity) account for ~2,900 commits. - 2020 onward: the community contributes regularly via small PRs (rendering tweaks, locale fixes, packaging support); top external committers include
bitraid(40),Jan Edmund Lazo(29),LangLangBart(26),Koichi Murase(19),Vlastimil Ovčáčík(14). - Bot activity is dominated by
dependabot[bot](98 commits).
The project remains effectively maintainer-led: ~92% of all commits are from the core author.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.