sharkdp/fd
CLI parsing
Active contributors: tmccombs, sharkdp
Purpose
This subsystem turns argv into the immutable Config that the rest of the binary reads. It owns the entire flag definition, the smart-case logic, the override semantics for paired --foo/--no-foo flags, and a custom parser for -x/-X because clap's derive API cannot model "everything until ; is one positional argument".
Directory layout
src/
├── cli.rs # Opts struct (clap derive), enums, custom Exec parser, default_num_threads
├── main.rs # construct_config, build_pattern_regex, build_regex,
│ # ensure_search_pattern_is_not_a_path, ensure_use_hidden_option_for_leading_dot_pattern
├── config.rs # The Config struct, populated by construct_config
└── regex_helper.rs # pattern_has_uppercase_char, pattern_matches_strings_with_leading_dotKey abstractions
| Type | File | Purpose |
|---|---|---|
Opts |
src/cli.rs |
clap-derived struct holding every flag. About 950 lines, including long help texts. |
Exec |
src/cli.rs |
Manual clap::FromArgMatches + clap::Args impl that handles -x/-X argv terminators. |
Config |
src/config.rs |
The post-parse, post-policy bag of settings consumed by walker/filters/output. |
FileType |
src/cli.rs |
clap ValueEnum for -t: file/f, directory/d/dir, symlink/l, block-device/b, char-device/c, executable/x, empty/e, socket/s, pipe/p. |
ColorWhen, HyperlinkWhen, StripCwdWhen |
src/cli.rs |
clap ValueEnums for --color, --hyperlink, --strip-cwd-prefix. |
pattern_has_uppercase_char |
src/regex_helper.rs |
The smart-case oracle. Walks the parsed regex_syntax::Hir to check for any literal or class containing an uppercase character. |
How it works
graph TD
argv[argv] -->|clap derive| opts[Opts]
opts -->|gen_completions?| completions[print_completions<br/>and exit]
opts -->|opts.search_paths| paths[Vec PathBuf]
opts -->|build_pattern_regex| pre_regex[Vec String<br/>raw regex sources]
pre_regex -->|construct_config| config[Config]
pre_regex -->|build_regex| regex[Vec Regex]
config --> walk[walk::scan]
regex --> walk
paths --> walkOpts::parse()runs the clap-derive parser. Help and version handling is automatic.- If
--gen-completions <shell>was given (and thecompletionsfeature is on),print_completionswrites the script viaclap_complete::generateand the program exits. set_working_dirhonours--base-directorybychdir-ing.opts.search_paths()collects positional--search-pathand[path]...values, falling back to["."].build_pattern_regexconverts the user's pattern depending on mode: glob →globset::GlobBuilderregex, fixed-strings →regex::escape, default → as-is.construct_configderives every effective setting:- Smart case. True unless
--ignore-case, or the user passed--case-sensitive, or any pattern contains an uppercase character. - Path separator.
--path-separatorif set; elsedefault_path_separator()(which only kicks in for MSYS on Windows); elseMAIN_SEPARATOR. On Windows, separators must be exactly one byte (check_path_separator_length). - Color.
Always/NeverorAuto— the latter combinesenable_ansi_support()(Windows),NO_COLOR, andis_terminal()on stdout. If colored,LsColors::from_env()falls back to the bundledDEFAULT_LS_COLORSconstant. - Hyperlink. Maps
Autoto whatever the color decision was, so hyperlinks follow color emission by default. - Command.
--exec/--exec-batchpopulateOpts::exec.--list-detailssynthesises anls -lhd --color=…template viadetermine_ls_command, picking GNUglson macOS/BSD when present. - File types. Each
-tflag toggles a boolean inFileTypes.-t executableimpliesfiles;-t emptyalone implies both files and directories. - Extensions. Compiled into a single case-insensitive
RegexSetof\.<ext>$patterns. - Time constraints. Both
--changed-withinand--changed-beforeflow throughTimeFilter::after/::before, with descriptive errors otherwise.
- Smart case. True unless
- Two friendly diagnostics run after
Configexists:ensure_search_pattern_is_not_a_pathrejectsfd /etc/passwd(without--full-path) with a hint pointing the user at the right command.ensure_use_hidden_option_for_leading_dot_patternnotices when the pattern only matches dotfiles but--hiddenwas not passed.
build_regexturns each pattern source into aregex::bytes::Regexwithcase_insensitive(!case_sensitive)anddot_matches_new_line(true). Errors here recommend--fixed-stringsor--glob.
The Exec parser
clap's derive API can't model a positional with a ; terminator that may include leading - arguments. So src/cli.rs defines an Exec newtype with manual FromArgMatches/Args impls. The args are declared with value_terminator(";"), allow_hyphen_values(true), and num_args(1..). The parser collects each occurrence of --exec or --exec-batch, passes the captured groups through CommandSet::new or CommandSet::new_batch, and stores the result on Opts::exec.
The user-facing rule — "everything after -x/-X belongs to the command, terminate with \; if you need more fd args" — is implemented entirely by these clap settings.
Override semantics
Many flags ship with both an enable form (--hidden) and a disable form (--no-hidden), so users can override values set elsewhere (e.g. shell aliases). The pattern in Opts is:
#[arg(long, short = 'H', help = "Search hidden files and directories", long_help)]
pub hidden: bool,
#[arg(long, overrides_with = "hidden", hide = true, action = ArgAction::SetTrue)]
no_hidden: (),The hidden () field exists only to consume the override — clap reads it but the field itself is never used by fd code.
Smart case in detail
pattern_has_uppercase_char parses each pattern with regex_syntax::ParserBuilder::new().utf8(false).build() and recursively walks the Hir:
- Literal bytes: any uppercase byte triggers
true. - Unicode class ranges: any range whose start or end is uppercase triggers
true. - Byte class ranges: same, treating each byte as a
char. - Captures and repetitions recurse into the inner hir.
- Concats and alternations recurse into all children.
Because the parser runs over the raw user pattern (including escaped sequences like \.), the function correctly does not flag \Acargo or \x6F as uppercase.
Entry points for modification
- To add a new flag: add a field to
Optsinsrc/cli.rs, document it (clap uses doc comments for--help), then read it inconstruct_config(src/main.rs) and store the derived value onConfig. If the flag is paired with a--no-foooverride, follow the existing pattern with a hidden()companion field. - To change smart-case behaviour: edit
pattern_has_uppercase_char(src/regex_helper.rs) and add a unit test next to it. - To extend
--list-details: editdetermine_ls_commandinsrc/main.rs. It already branches on Linux vs macOS/BSD vs Windows. - To support a new completion shell: depend on a newer
clap_complete::Shellvariant; nothing else needs to change inprint_completions.
Related pages
- Walker — what consumes the
Configyou build here. - Command execution — what the
Execparser produces. - Format templates — shared by
--execand--format.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.