Open-Source Wikis

/

fd

/

Systems

/

Format templates

sharkdp/fd

Format templates

Active contributors: tmccombs, sharkdp

Purpose

A single, small template engine that handles both --exec/--exec-batch placeholders and the --format output template. It parses a template string into a sequence of tokens (literal text and placeholder kinds), then expands each token against a path, optionally rewriting path separators along the way.

Directory layout

src/
└── fmt/
    ├── mod.rs    # Token, FormatTemplate, parser, generator, replace_separator
    └── input.rs  # basename, dirname, remove_extension helpers used by generator

Key abstractions

Type File Purpose
Token src/fmt/mod.rs Placeholder, Basename, Parent, NoExt, BasenameNoExt, or Text(String).
FormatTemplate src/fmt/mod.rs Either Tokens(Vec<Token>) (template with at least one placeholder) or Text(String) (literal).
replace_separator src/fmt/mod.rs Replaces MAIN_SEPARATOR with the user-chosen --path-separator, with special handling for Windows UNC and drive prefixes.
basename, dirname, remove_extension src/fmt/input.rs Path helpers that match the documented placeholder semantics.

Placeholders

Token Literal Meaning Example for documents/images/party.jpg
Placeholder {} Full path documents/images/party.jpg
Basename {/} File name party.jpg
Parent {//} Parent directory documents/images
NoExt {.} Path without final extension documents/images/party
BasenameNoExt {/.} Basename without final extension party
Literal { {{ An actual { character
Literal } }} An actual } character

Parsing

FormatTemplate::parse uses an aho_corasick::AhoCorasick matcher over the seven literal patterns ["{{", "}}", "{}", "{/}", "{//}", "{.}", "{/.}"]. The match handler:

  • On {{ or }}, copy the text up to the first brace into the buffer, then skip the second brace. This implements the escape rules.
  • On a placeholder pattern, push any pending text as Token::Text, then push the corresponding Token variant.
  • On a placeholder pattern immediately followed by } (e.g. {}}), treat the trailing } as escaped and add it to the buffer. This is what allows the test case "{{{},end}""{foo,end}".

If no placeholder pattern matched, the template collapses to FormatTemplate::Text(buf). Otherwise, every leftover buffer chunk becomes a final Token::Text.

The fixed AhoCorasick is built once and stored in a static OnceLock so subsequent parses are allocation-light.

Generation

FormatTemplate::generate(path, path_separator) walks the token list and pushes the right thing into a fresh OsString:

  • Placeholder → the full path, possibly with separators rewritten.
  • Basenamebasename(path) (which is path.file_name() falling back to the path itself if there is no name component).
  • Parentdirname(path) (path.parent() with empty parent normalised to ".", falling back to the path's OsStr if the parent is None).
  • NoExtremove_extension(path) (dirname joined with path.file_stem(), then strip_current_dir).
  • BasenameNoExtremove_extension(basename(path)).
  • Text(s) → just appended verbatim. Path separator substitution does not apply to literal text in the template.

FormatTemplate::Text(text) is generated with no per-path computation.

Path separator substitution

replace_separator is the trickiest part. It is invoked on placeholder substitutions only, never on literal text. The implementation iterates over Path::components() and:

  • For Windows Component::Prefix(UNC(server, share)), emits {sep}{sep}server{sep}share.
  • For other Windows prefixes (drive letters, etc.), emits the prefix as-is — drive letters like C: are preserved.
  • For Component::RootDir, emits the custom separator.
  • For all other components, emits the component bytes followed by the separator if there is another component coming.

Forward slashes on Windows are normalised by Path::components() itself, so "C:/foo/bar" becomes the same components as "C:\\foo\\bar". Verbatim prefixes (\\?\…) are intentionally left as-is on the basis that anyone using them is already past the point of caring about pretty separators.

Where it is used

  • --format. Config::format is set when --format is on. output::print_entry_format calls format.generate(stripped_path, path_separator) and writes the resulting string. FormatTemplate::Text short-circuits to a no-op OsString containing just the literal template.
  • --exec/--exec-batch. Each argv element is a FormatTemplate. CommandTemplate::generate (in src/exec/mod.rs) walks them and feeds each into argmax::Command::try_arg. CommandTemplate::new automatically appends a final Token::Placeholder if the user template contains no placeholder, which is what makes fd -e zip -x unzip work without writing unzip {} explicitly.

Helpers in src/fmt/input.rs

pub fn basename(path: &Path) -> &OsStr {
    path.file_name().unwrap_or(path.as_os_str())
}

pub fn dirname(path: &Path) -> OsString {
    path.parent()
        .map(|p| if p == OsStr::new("") { OsString::from(".") } else { p.as_os_str().to_owned() })
        .unwrap_or_else(|| path.as_os_str().to_owned())
}

pub fn remove_extension(path: &Path) -> OsString {
    let dirname = dirname(path);
    let stem = path.file_stem().unwrap_or(path.as_os_str());
    let path = PathBuf::from(dirname).join(stem);
    strip_current_dir(&path).to_owned().into_os_string()
}

strip_current_dir (src/filesystem.rs) trims a leading ./, so remove_extension(Path::new("foo.txt")) returns "foo", not "./foo". The unit-test table in src/fmt/input.rs covers UTF-8 filenames ("💖.txt""💖"), nested dirs, hidden files (.foo keeps its dot because it has no extension to strip), and the empty path.

Entry points for modification

  • Add a new placeholder. Add a Token variant, extend the aho-corasick pattern list, update Display, and add a match arm in generate. Add a unit test in src/fmt/mod.rs.
  • Change separator handling for a new prefix kind. Edit replace_separator's Component::Prefix arm.
  • Change basename/dirname semantics. Edit src/fmt/input.rs and update the unit-test table.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Format templates – fd wiki | Factory