junegunn/fzf
Core coordinator
Purpose
src/core.go owns the lifecycle of an interactive fzf run. The Run function constructs the Reader, Matcher, and Terminal, kicks off their goroutines, and spins an event loop that drains a util.EventBox until the user accepts, aborts, or the input runs out.
It also handles the non-interactive --filter mode (which short-circuits to a single scan and print) and the benchmark mode (--bench).
Directory layout
src/
├── core.go # Run() and the event-loop coordinator
├── constants.go # ExitOk/ExitError/..., chunkSize, slab sizes, poll intervals
├── functions.go # Small inline helpers used by core
└── proxy.go # Process-mode wrapper invoked before Run when applicableKey abstractions
| Symbol | File | Description |
|---|---|---|
Run(opts *Options) (int, error) |
src/core.go |
Top-level entry point called from main.go. Returns an exit code and an optional error. |
revision |
src/core.go |
(major, minor) counter bumped on input mutations; used to invalidate match caches. |
EvtReadNew, EvtReadFin, EvtSearchNew, EvtSearchProgress, EvtSearchFin, EvtQuit |
src/core.go |
The events drained by the coordinator. |
searchRequest |
src/core.go |
Payload sent from Terminal to Matcher when query/sort/nth/with-nth/header-lines/denylist changes. |
quitSignal |
src/core.go |
Wraps the exit code and error when the Terminal asks to terminate. |
fitpad |
src/core.go, src/terminal.go |
Pair (fit, pad) describing the height and pad fzf should occupy; used for --height adaptive mode. |
How it works
graph TD
RUN[Run] --> POPUP{Popup or<br/>winpty?}
POPUP -- yes --> PROXY[runProxy]
POPUP -- no --> POST[postProcessOptions]
POST --> CHUNKS[NewChunkList]
POST --> READER[NewReader]
POST --> TERMINAL[NewTerminal]
POST --> MATCHER[NewMatcher]
POST --> LOOP[Coordinator loop]
LOOP --> WAIT[eventBox.Wait]
WAIT --> READ[Handle Read events:<br/>snapshot, reset matcher]
WAIT --> SEARCH[Handle Search events:<br/>update list, update progress]
WAIT --> QUIT[Handle EvtQuit:<br/>exit]
LOOP -. delay .-> LOOPThe body of Run reads almost like a script:
- Pre-launch checks.
opts.useTmux(),opts.useZellij(), andneedWinpty(opts)route torunTmux,runZellij, orrunWinptyrespectively before any goroutines start. See Process modes. - Post-process options.
postProcessOptionsvalidates and finalizes the parsed options. - Construct primitives.
NewChunkCache,NewChunkList,NewReader,NewMatcher,NewTerminal,util.NewEventBox. - Kick off Reader.
go reader.ReadSource(...)runs the configured input source in its own goroutine. Read source can be: a Go channel passed viaopts.Input, a child process (FZF_DEFAULT_COMMANDor--bind=start:reload), the built-in walker, or stdin. - Filter mode short-circuit. If
opts.Filter != nil, the coordinator runs a single scan/print and returns immediately. Streaming filter (when--no-sortand--no-tacand!--sync) runs the matcher line-by-line as items are read, never building a chunk list snapshot for sorting. - Start Matcher and Terminal.
go matcher.Loop()andgo terminal.Loop()then enter the event loop. - Coordinator loop. Drains
eventBox.Wait. On each event:EvtReadNew/EvtReadFin→ snapshot the chunk list, update the count, possibly reset the matcher.EvtSearchNew→ apply mutations fromsearchRequest(nth, with-nth, header-lines, reload command, denylist), bump revision if needed, thenmatcher.Reset(...).EvtSearchProgress→ forward the percentage to the terminal.EvtSearchFin→ push the match list to the terminal; handle the deferred-start case for--height=~,--select-1,--exit-0,--sync.EvtQuit→ propagate the exit code and break the loop.
- Adaptive sleep. While reading, the loop sleeps for
min(ticks * coordinatorDelayStep, coordinatorDelayMax)to avoid spamming CPU when items arrive in tiny bursts. - Cleanup.
defer util.RunAtExitFuncs()runs registered cleanup hooks (temp files, fifos, sockets) beforeRunreturns.
Integration points
- From
main.go: the binary callsfzf.Run(options)once, prints any error to stderr, and exits with the returned code. - To
Reader(src/reader.go): the coordinator owns theReader's lifecycle. It can callreader.terminate()to kill the running command and start a new one (forreloadandreload-sync). - To
Matcher(src/matcher.go):matcher.Reset(snapshot, query, ...)is called on every relevant event.matcher.Stop()is deferred for clean shutdown. - To
Terminal(src/terminal.go):terminal.UpdateCount,terminal.UpdateHeader,terminal.UpdateProgress,terminal.UpdateListall flow from the coordinator. The coordinator never reads back from the terminal except via the event box. runProxyinsrc/proxy.gocalls back intoRunindirectly by re-execing the binary with the popup or winpty wrapper.
Entry points for modification
- Adding a new event: declare it in the
EventTypeblock ofsrc/core.go, add acasein the event-loop switch, and a producer somewhere (Reader, Matcher, Terminal). Make sure theWatch/Unwatchcalls are updated if the event needs to be coalesced. - Adding state that should reset on
reload: thread it throughrestart(the inner closure inRun) and callbumpMajoron the revision. - Changing the deferred-start behavior: the
determine,deferred, andheightUnknownvariables coordinate the--select-1/--exit-0/--sync/--height=~cases. They are tightly coupled — read the comments incore.gocarefully before tweaking.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.