luff
Print files with formatting
Features
- Multiple Output Formats: Markdown blocks, tree view
- Smart File Discovery: Directory walking with gitignore support
- Glob Pattern Support: Explicitly ignore files using bash-style patterns
- Clipboard Integration: Copy output directly to system clipboard
- Config File Support: YAML configuration with JSON Schema for IDE autocomplete
- Security Hardened: Protection against path traversal, symlink attacks, resource exhaustion
- High Performance: Upfront collection with minimal allocations, efficient I/O
- Well Tested: Unit tests, property-based tests, integration tests, E2E tests
- Modular Architecture: Clean separation of concerns, easy to extend
Installation
From Source
Development Build
Usage
Process Specific Files
Files can be passed as positional arguments or via the -f flag:
Walk Current Directory
Print all files in the current directory:
Walk from Git Root
Start from the git repository root:
Include Ignored Files
Include files that .gitignore would normally skip:
Explicitly Ignore Files
Ignore files matching glob patterns (in addition to .gitignore):
Multiple patterns can be passed to a single --ignore flag:
Include Hidden Files
Include dot-directories and dotfiles:
Override a config file that enables dotfiles:
Tree Output Format
Display as a tree structure:
Limit Directory Depth
Only traverse up to N levels deep:
Limit File Count
Cap the number of files collected during a directory walk:
Copy to Clipboard
Copy output to system clipboard (also prints to stdout):
Clipboard Only (No Stdout)
Copy to clipboard without printing to terminal:
Use a Config File
Load settings from a YAML config file:
Generate Config Schema
Generate a JSON Schema for config file validation and IDE autocomplete:
Enable Debug Logging
Show detailed information about file processing:
Combined Options
# Walk git repo, include ignored files, include dotfiles, debug output
# Process specific files with tree format
# Walk with depth limit and copy to clipboard
# Clipboard-only mode with tree format
Options
| Flag | Long | Description |
|---|---|---|
<FILE>... |
Process specific files (positional, disables directory walk) | |
-f |
--files <FILE>... |
Process specific files (flag form, disables directory walk) |
--config <PATH> |
Path to config file (YAML format) | |
-g |
--git |
Start from git repository root |
--dotfiles |
Include hidden files/directories | |
--no-dotfiles |
Exclude hidden files/directories (overrides config) | |
-a |
--add |
Add files normally ignored by .gitignore |
-i |
--ignore <PATTERN>... |
Explicitly ignore files matching glob patterns |
-c |
--clip |
Copy output to clipboard (also prints to stdout unless -S) |
-S |
--suppress-stdout |
Suppress stdout output (useful with -c for clipboard-only) |
-v |
--verbose |
Enable debug logging |
--format <FORMAT> |
Output format: markdown (md), tree (default: markdown) |
|
--max-depth <N> |
Maximum directory depth (0 = unlimited, default: 0) | |
--max-files <N> |
Maximum files to collect during walk | |
--max-clipboard-mb <N> |
Maximum clipboard size in MB (default: 100, hard limit: 1000) | |
-h |
--help |
Print help information |
-V |
--version |
Print version information |
Subcommands
| Command | Description |
|---|---|
schema |
Generate JSON Schema for config files (for IDE autocomplete) |
Output Modes
| Flags | Behavior |
|---|---|
| (none) | Stream to stdout (default, low memory) |
-c |
Buffer entire output, write to stdout AND clipboard |
-c -S |
Buffer entire output, copy to clipboard only (no stdout) |
-S |
No output (edge case, allowed but not useful) |
Note: Clipboard mode requires buffering the entire output in memory before writing. For large codebases, this may use significant memory. Use --max-clipboard-mb to control the limit.
Architecture
Key Design Decisions
- Upfront Collection: Directory walker collects file paths at construction to prevent output file inclusion
- Shell Redirection Protection: Skips empty files created within 2 seconds to avoid including
luff > output.txtoutput - Printer Actor: Bounded channel (capacity 16) to a dedicated writer thread for contention-free stdout
- Zero-cost Abstractions: Walker enum provides unified interface without runtime overhead
- Security First: All file operations validated against path traversal, size limits, symlink attacks
- Explicit Error Handling: No panics in library code,
Resulttypes throughout
Development
Prerequisites
- Rust 1.85 or later
- Git (for git-related functionality)
- Clipboard support (X11/Wayland on Linux, native on macOS/Windows)
Building
Testing
Benchmarking
Code Quality
Security
This project follows security best practices:
- Path Validation: All paths validated against traversal attacks
- Size Limits: Files limited to 100MB to prevent memory exhaustion
- TOCTOU Protection: File metadata re-checked after open
- Symlink Safety: Canonicalization with validation
- Input Sanitization: All user input validated
- No Unsafe Code: Pure safe Rust (verify with
cargo geiger) - Root Containment: File list mode prevents access outside project root
- Timeout Protection: File operations have 5-second timeout to prevent FIFO blocking
Platform Support
- Linux: Full support (X11 or Wayland required for clipboard)
- macOS: Full support (native clipboard)
- Windows: Full support (native clipboard)
- Headless: Works without clipboard (graceful degradation)