Open-Source Wikis

/

fzf

/

Lore

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--preview and the placeholder substitution machinery in src/terminal.go opened the door to building rich pickers (file viewers, git previews, kubectl describe, etc.).
  • Popup mode--tmux (src/tmux.go) and later --popup for Zellij (src/zellij.go) wrap fzf in a floating terminal, implemented via the runProxy indirection in src/proxy.go.
  • --listen (added in 0.36) — an HTTP control plane in src/server.go that lets external programs send actions to a running fzf. Re-bind keys, change the preview, reload the list, all over POST / 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; --print0 has been the toggle since the Go rewrite.
  • --filter mode: non-interactive filtering shipped with the original Ruby version and survived the Go rewrite essentially intact (src/core.go still has a clearly delineated branch for it).
  • --ansi: the ANSI escape-sequence-aware tokenizer has been around since 2014; src/ansi.go still resembles its early form, just with more edge cases.
  • fzf-tmux: the bin/fzf-tmux wrapper predates the in-binary --tmux popup 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; see CHANGELOG.md for breaking changes between 0.x releases.
  • Custom border tags that predated the unified --style preset 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.go was retrofitted so the fast custom renderer (light.go) could coexist with tcell.go, gated by a build tag.
  • Walker: the file system walker was migrated to github.com/charlievieth/fastwalk for parallel directory traversal; src/reader.go retains 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 Choi and junegunn (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.

Lore – fzf wiki | Factory