junegunn/fzf
Options and the action language
Purpose
src/options.go parses the command line, validates options, and exposes a populated Options struct that the rest of the program consumes. It also defines the action-language enum and the parsing rules for --bind. It's the largest single file in the codebase after src/terminal.go (~3,950 lines), and almost every user-visible feature touches it at some point.
Directory layout
src/
├── options.go # The big one: ParseOptions, all flags, action types.
├── options_test.go
├── options_pprof.go # Build tag: pprof. Adds --profile-* flags.
├── options_no_pprof.go # Default build. Stub.
├── options_pprof_test.go
├── actiontype_string.go # Generated by stringer.
└── constants.go # ExitCodes, sizes, intervals.Key abstractions
| Symbol | Description |
|---|---|
Options |
Holds every parsed setting. Fields cover search, IO, display, key bindings, preview, popup, listen, walker, scoring scheme, etc. |
ParseOptions(...) |
Top-level entry. Builds an Options from os.Args (or any []string). |
Usage |
Multi-line const containing the help text printed by --help. |
actionType |
An iota enum with 200+ values (actAccept, actAbort, actReload, actBecome, actChangePreview, ...). The string form is in the generated actiontype_string.go. |
action |
A single instance of an action with optional argument (e.g. actExecute("rg {}")). |
actionList |
An ordered list of actions chained via +. |
Keymap |
map[tui.Event]actionList — the parsed --bind values. |
parseKeyChords, parseKeymap |
Parse user-supplied bind strings. |
parseAction, parseActionList |
Tokenize the action expression in a bind. |
parsePlaceholder (in terminal.go) |
Pairs with the parsing here for placeholders inside action arguments. |
BorderShape (re-used from tui) |
Validated by parseBorder. |
walkerOpts |
Built-in file system walker config (file, dir, hidden, follow). |
Tmux (struct) |
Position, size, and border for the --tmux popup. |
Color / ColorTheme (re-used from tui) |
Validated by parseTheme. |
Delimiter, Range (in tokenizer.go) |
Parsed for --nth, --with-nth, --accept-nth. |
How it works
Parsing approach
Rather than using flag or a third-party library, ParseOptions is a hand-written iterator over the argument slice. It supports:
- Long and short forms (
--exact/-e,--ignore-case/-i). --key=valueand--key value.- Boolean inversion (
--boldvs--no-bold,--mousevs--no-mouse). - Composite flags whose value is a small DSL, parsed by dedicated helpers (
--bind,--color,--style,--preview-window,--header-border,--info,--tmux,--listen, etc.). - Reading defaults from
FZF_DEFAULT_OPTSand a file pointed at byFZF_DEFAULT_OPTS_FILE, before overlaying CLI args.
The parser is forgiving about ordering: FZF_DEFAULT_OPTS=--reverse fzf --no-reverse works as expected because the second pass overwrites.
The action language
A --bind value is a comma-separated list of event:action[+action]* pairs. For example:
--bind 'ctrl-r:reload(rg --files)+clear-query,enter:become(vim {}),change:first'Events are either:
- A key chord:
ctrl-a,alt-up,f5,tab,shift-tab,enter,space, mouse events (click,right-click,double-click,scroll-up,scroll-down, etc.). - A named event:
start,load,change,result,focus,one,zero,jump,jump-cancel,multi,backward-eof. - Bracketed paste boundaries.
Actions take optional arguments:
execute(...),execute-silent(...),become(...),reload(...),reload-sync(...),transform-query(...),transform-prompt(...),transform-header(...),transform-search(...),change-preview(...),change-prompt(...),change-query(...),put(...),pos(...),unbind(...),rebind(...),toggle-bind(...), etc.- The argument can use any delimiter that consistently brackets the value:
reload(...)andreload:...both work. +chains actions. They run in order; if one of them isacceptorabort, the rest still execute up to the terminating action.
parseAction walks the value byte-by-byte to honor escapes, balanced parentheses, and shell-style quoting. The result is a []action.
The named action arguments interact with the placeholder language defined in src/terminal.go (see Terminal UI).
Lazy / transform-* options
A subset of options can be either:
- A literal value, e.g.
--prompt='> ',--query='foo',--nth=2,3. - A shell command whose stdout is read at runtime and treated as the value, via the matching
transform-*action.
For example, --bind 'change:transform-prompt(echo "{q}> ")' recomputes the prompt every time the query changes. The mechanism is implemented inside terminal.go's action engine, but the wiring lives in options.go where the action token is parsed.
Build-tagged option families
When built without the pprof tag, options_no_pprof.go is compiled and the profile flags are no-ops. With -tags pprof, options_pprof.go provides real implementations using runtime/pprof. The user-visible flag list in Usage does not mention these unless the binary supports them — the Usage constant is shared and the implementation gates the actual behavior.
Validation
postProcessOptions (called from core.go) finalizes the Options: cross-flag consistency (e.g. --filter requires --no-sync?), defaults that depend on the terminal (--height only meaningful interactively), and --listen initialization (parses the address, generates an API key).
Integration points
- From
main.go:fzf.ParseOptions(true, os.Args[1:])is called once. - To
core.go: the populated*Optionsis passed toRun. Almost every field is used somewhere downstream. - To
terminal.go: the action engine consumesOptions.Keymapand the various per-action argument fields. - To
server.go: the listen-mode body strings are parsed back into actions by re-using the sameparseActionmachinery.
Entry points for modification
- New flag:
- Add a field to
Options. - Extend the parsing switch in
ParseOptions. - Document it in the
Usageconstant. - Update
man/man1/fzf.1andCHANGELOG.md. - Add tests in
src/options_test.go(parsing) andtest/*.rb(behavior).
- Add a field to
- New action:
- Add a constant to the
actionTypeenum. make generateto refreshsrc/actiontype_string.go.- Wire it in
parseAction(so--bind 'enter:my-action(arg)'parses). - Implement the behavior in
src/terminal.go. - Document and test as above.
- Add a constant to the
- New placeholder: see Terminal UI. Most placeholder work is in
terminal.go;options.goonly needs changes if the placeholder is recognized at parse time (rare). - Tweak default: changing a default has knock-on effects across
Usage, the integration tests (which often pin the default in their expected output), andCHANGELOG.md.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.