Projects/Build a Fuzzy Finder

Build a Fuzzy Finder

Start with a one-line subsequence test and end with a real fuzzy finder that filters a corpus, ranks matches like fzf, highlights where each query character landed, and narrows interactively as you type. Every lesson gives you a concrete spec with exact scores and positions to hit, and the finder grows one honest piece at a time - matching, scoring, an optimal alignment, ranking, and an interactive loop.

34 lessonsSmall~20 min / lessonSubsequence matchingDynamic programmingRanking
The project

What you'll build over the next 34 lessons

Over 34 lessons you build a working fuzzy finder in the spirit of fzf. You begin with the core question - does a query fuzzy-match a candidate, character by character, in order - and grow it into a scoring model that rewards consecutive matches, matches at word and path boundaries, and camelCase humps, while penalizing gaps and a slow start. A dynamic-programming pass then finds the highest-scoring alignment (not just any match) and traces back the exact positions, which drive highlighting. From there you rank a whole candidate list, add fzf-style extended query syntax (exact, anchored, and negated terms), and wrap it all in an interactive finder that narrows as you type.

By the end you have a runnable tool: a non-interactive filter mode (pipe a list in, get the ranked, highlighted matches out) and an interactive finder model - query state, selection movement, keystroke handling, and a rendered frame - driven over a real corpus such as a file listing. The capstone runs a scripted interactive session over a file tree and proves the ranked frames and the accepted path are exactly what the design predicts.

This is a teaching-grade finder built around fzf's real algorithm: correct, ranked, and genuinely usable, but it stops short of what fzf ships on top - a full-screen ANSI-themed terminal UI with a preview window, multi-select, Unicode normalization, asynchronous loading of a still-streaming corpus, and every nuance of fzf's tuned scoring. What you finish with is the honest core all of those are built around.

build-a-fuzzy-finder / lesson-01.md
Lesson 01 · Matching

The candidate stream

A fuzzy finder is a filter over a stream of candidate lines - a list goes in, a smaller list comes out. Today you build the smallest possible version - one that reads candidates and prints them all back - so there is a runnable tool from day one that every later lesson thickens.

The goal

Read newline-separated candidates from standard input and print each one back unchanged.

Start here - the target
TO DO
Scenario: Echoing every candidate line
Giventhe three input lines "src/main.go", "README.md", and "go.mod" on standard input
Whenthe program runs with no query
Thenit prints the same three lines, in the same order, one per line
Andempty input prints nothing and exits cleanly
Background

Every fuzzy finder is, at heart, a filter over a list of candidates: file paths, command history, lines of a buffer. Before any matching or scoring matters, that pipe has to exist - something you can run, feed a list of lines, and watch come out the other end. Today it passes everything through, so running it is the identity function on your input.

Starting with a runnable entry point is deliberate. The finder will grow one capability at a time - a match test, a score, a ranking - and at every step you will be able to run the tool and see the effect on real input. A candidate is just a line of text; keeping that definition dead simple now means nothing downstream has to care where the lines came from.

Make it work
// Read stdin line by line and echo. This is the walking skeleton -
// it does no filtering yet. Every candidate is a "line".
sc := bufio.NewScanner(os.Stdin)
for sc.Scan() {
line := sc.Text()
fmt.Println(line)
}
CheckpointDONE
You have a runnable tool that streams candidates through untouched. Commit and stop here.
Scope & extensions

Where this project stops - and where to go next

A complete, usable fuzzy-finder engine - smart-case subsequence matching, the boundary- and camelCase-aware dynamic-programming scorer, ranking with tie-breaks, and fzf-style extended query syntax - shared across a non-interactive filter mode, a real interactive terminal finder, and a zero-setup demo; the interactive terminal loop is deliberately minimal (ASCII keys, no resize handling) rather than a full-screen fzf clone.

Extend it next
  • Wire the bounded top-K fast path into the live keystroke loop so a very large corpus stays responsive as you type
  • Reassemble UTF-8 runes in the key decoder so non-ASCII candidates and queries work in interactive mode
  • React to terminal resize (SIGWINCH) to reflow the visible row count mid-session
  • Give cancel (Esc / Ctrl-C) a distinct non-zero exit code, the way fzf returns 130
  • Add multi-select (Tab to mark several candidates and accept the set), fzf's -m flag
  • Add a preview window and ANSI color themes for the selected candidate
Recommended reading

Books & references that go deeper

  • fzf · Junegunn Choi

    The command-line fuzzy finder this project is modeled on. Its src/algo package documents the exact boundary- and gap-aware scoring you build here.

  • The clearest walk-through of a practical fuzzy-match scorer - consecutive, boundary, and camelCase bonuses plus gap penalties - the model this project uses.

  • The local sequence-alignment dynamic program that the best-match pass is a scoring variant of - fill a table, then trace back the optimal path.

  • selecta · Gary Bernhardt

    A small, readable fuzzy selector whose README explains, from first principles, why a good finder ranks by match quality rather than just filtering.

  • skim · Jinzhou Zhang

    A fuzzy finder that reimplements the fzf model in another language - a useful second reference for the scoring and ranking design.