# luff
Print files with formatted metadata
[](LICENSE)
[](https://www.rust-lang.org)
## 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
- **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
```bash
git clone https://github.com/owlroute/luff.git
cd luff
cargo install --path .
```
### Development Build
```bash
cargo build --release
./target/release/luff --help
```
## Usage
### Process Specific Files
Print specific files with Markdown formatting:
```bash
luff -f src/main.rs Cargo.toml
```
### Walk Current Directory
Print all files in the current directory:
```bash
luff
```
### Walk from Git Root
Start from the git repository root:
```bash
luff -g
```
### Respect .gitignore (default)
Honor gitignore patterns when walking (on by default):
```bash
luff
```
### Include Ignored Files
Include files that .gitignore would normally skip:
```bash
luff --add
```
### Explicitly Ignore Files
Ignore files matching glob patterns (in addition to .gitignore):
```bash
luff --ignore "*.log" --ignore "target/**"
```
### Include Hidden Files
Include dot-directories and files:
```bash
luff -d
```
### Tree Output Format
Display as a tree structure:
```bash
luff --format tree
```
### Limit Directory Depth
Only traverse up to N levels deep:
```bash
luff --max-depth 3
```
### Copy to Clipboard
Copy output to system clipboard (also prints to stdout):
```bash
luff -c
```
### Clipboard Only (No Stdout)
Copy to clipboard without printing to terminal:
```bash
luff -c -S
```
### Enable Debug Logging
Show detailed information about file processing:
```bash
luff -v
```
### Combined Options
```bash
# Walk git repo, include ignored files, include dotfiles, debug output
luff -g -a -d -v
# Process specific files with tree format
luff -f src/*.rs --format tree
# Walk with depth limit and copy to clipboard
luff --max-depth 2 -c
# Clipboard-only mode with tree format
luff --format tree -c -S
```
## Options
| `-f` | `--files <FILES>...` | Process specific files (disables directory walk) |
| `-g` | `--git` | Start from git repository root |
| `-d` | `--dotfiles` | Include hidden files/directories |
| `-a` | `--add` | Add files normally ignored by .gitignore |
| `-i` | `--ignore <PATTERN>` | Explicitly ignore files matching glob pattern |
| `-c` | `--clip` | Copy output to clipboard (also prints to stdout unless -S used) |
| `-S` | `--suppress-stdout` | Suppress stdout output (useful with -c for clipboard-only) |
| `-v` | `--verbose` | Enable debug logging |
| | `--format <FORMAT>` | Output format: markdown, tree (default: markdown) |
| | `--max-depth <N>` | Maximum directory depth (0 = unlimited, default: 0) |
| `-h` | `--help` | Print help information |
| `-V` | `--version` | Print version information |
## Output Modes
| (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.
## 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.txt` output
- **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, Result types throughout
## Development
### Prerequisites
- Rust 1.85 or later
- Git (for git-related functionality)
- Clipboard support (X11/Wayland on Linux, native on macOS/Windows)
### Building
```bash
# Debug build
cargo build
# Release build (optimized)
cargo build --release
# Run with arguments
cargo run -- --help
```
### Testing
```bash
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run specific test
cargo test test_normalize_path
# Run integration tests only
cargo test --test integration_test
# Run E2E tests
cargo test --test e2e_test
# Run with property-based tests
cargo test --features proptest
```
### Benchmarking
```bash
# Run all benchmarks
cargo bench
# Run specific benchmark
cargo bench walker_small
# Generate HTML reports
cargo bench -- --save-baseline my-baseline
```
### Code Quality
```bash
# Check for issues
cargo clippy
# Format code
cargo fmt
# Check for unsafe code
cargo geiger
```
## 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)