tree

A cross-platform tree command written in Rust, providing a fast directory listing with features like glob filtering, icons, gitignore support, and colorized output. Works on Windows, macOS, and Linux.

Overview

  • Language: Rust
  • Repo: peteretelej/tree
  • Install: cargo install rust_tree --locked
  • Status: active (v1.3.0)

Architecture

This is a single-crate project (published as rust_tree on crates.io) with a thin binary and a full library surface.

Binary (src/main.rs): A 17-line wrapper that calls run_cli() and handles broken pipe errors gracefully. All logic lives in the library.

Library (src/lib.rs -> src/rust_tree/): Seven modules, each with a focused responsibility:

  • cli.rs - Argument parsing via clap derive, maps CLI flags to TreeOptions
  • options.rs - The TreeOptions struct, a flat config object with ~25 boolean/option fields controlling every aspect of output
  • traversal.rs - The core engine. list_directory() is the public API entry point, which delegates to either list_from_filesystem() or list_from_input() (for --fromfile mode). Recursive traversal via traverse_directory() which takes a generic Write sink, enabling both stdout and string capture (list_directory_as_string())
  • display.rs - ANSI colorization by file type/extension using ansi_term, plus Unix permission formatting
  • icons.rs - IconManager with a JSON-based icon theme system. Default theme is embedded as a const string with ~100 extension-to-emoji mappings, well-known filenames (Dockerfile, Cargo.toml), and fallback categories. Supports loading custom themes from file
  • gitignore.rs - Respects .gitignore rules during traversal, with per-directory rule extension
  • fromfile.rs - Parses file listings from stdin/file into a VirtualTree, enabling tree to display structure from piped input
  • utils.rs - Helpers like bytes_to_human_readable and is_broken_pipe_error

Data flow: CLI args -> TreeOptions -> list_directory(path, &options) -> recursive traverse_directory() with filtering, sorting, and entry formatting -> writes to a BufWriter<impl Write>.

Key Design Decisions

Library-first: The binary is intentionally thin. The list_directory and list_directory_as_string functions are the public API, making it usable as a Rust crate for programmatic directory listing.

Generic writer pattern: traverse_directory accepts impl Write, so the same traversal code powers both stdout output and string capture. The prune feature uses this too, probing subtrees by traversing into io::sink().

No chrono: Date formatting is implemented manually using stdlib’s SystemTime and manual calendar math, avoiding the chrono dependency and its cross-compilation complexity.

Icon system via JSON: Rather than hardcoding icons or using a match statement, the icon theme is a JSON structure deserialized at startup. This makes it extensible (custom theme files) while keeping the default embedded in the binary.

Windows 7 compatibility: The project maintains a separate Cargo-win7.lock lockfile for building with Rust 1.75 on Windows 7. The MSRV is pinned at the workspace level, and static CRT linking is configured for Windows targets.

Glob filtering: Uses the glob crate’s Pattern type for both include (-P) and exclude (-I) patterns, with support for pruning empty directories and matching directory names.

Development

cargo build --release
cargo test
cargo fmt --check
cargo clippy

# Run the pre-push quality script
./scripts/pre-push

# Windows 7 build
rustup run 1.75.0 cargo build --release