# Printer Module
**Purpose**: Output formatting abstraction - converts WalkerEntry to formatted stdout/string.
## File Responsibilities
### mod.rs
- **print_file()**: Dispatcher (OutputFormat → printer implementation)
- **PrinterOptions**: Config carrier (format + root + patterns)
- **Re-exports**: Public printer types
### markdown.rs
- **MarkdownPrinter::print()**: Stateless formatter, streams output to stdout
- **Streaming I/O**: Uses `BufReader` to process files in chunks (low memory footprint)
- **Binary Detection**: Checks first chunk for NUL bytes to skip binary files
- **UTF-8 Handling**: Streaming decoder handles split characters, replaces invalid sequences
- **Locked stdout**: Single lock per file for efficiency
### tree.rs
- **TreePrinter**: Stateful accumulator for batch mode
- **TreeNode building**: Constructs in-memory hierarchy from paths
- **Recursive printing**: Pretty-print with Unicode box-drawing
- **Streaming mode**: TreePrinter::print() for single entries
## Critical Types
```rust
PrinterOptions {
format: OutputFormat,
root: PathBuf, // For calculating relative paths in output
patterns: IgnorePatterns, // For filtering content (binary checks)
skip_patterns: SkipPatterns, // Whether to apply filtering
}
MarkdownPrinter // Zero-sized type (stateless)
TreePrinter {
entries: Vec<PathBuf> // For batch accumulation
}
```
## Critical Methods
```rust
print_file(entry, options) -> Result<()>
// Dispatcher, delegates to MarkdownPrinter or TreePrinter
MarkdownPrinter::print(entry, root, patterns, skip) -> Result<()>
// Streams: relative_path\n```ext\n[content]\n```\n
// Checks patterns and content (NUL bytes) before full stream
TreePrinter::print(entry, root) -> Result<()>
// Streaming: prints single entry with icon
TreePrinter::print_tree(&self, root) -> Result<()>
// Batch: prints accumulated tree structure
```
## Output Formats
### Markdown (fenced code blocks)
```
relative/path/to/file.rs
```rs
fn main() {}
```
```
### Tree (directory hierarchy)
```
📁 src
├── 📄 main.rs
└── 📁 config
└── 📄 mod.rs
```
## Key Invariants
- All printers write to stdout (no file handles passed in)
- stdout locked once per print_file() call (not per line write)
- Binary files filtered by extension AND content inspection (NUL check)
- Invalid UTF-8 is replaced with (lossy conversion), not skipped
- MarkdownPrinter streams data (O(1) memory), does not load full file
- TreePrinter requires full traversal + in-memory tree for hierarchy
## Performance Notes
- **Streaming**: MarkdownPrinter uses 8KB buffer, constant memory usage regardless of file size
- **Locked stdout**: Eliminates repeated lock/unlock overhead
- **Binary detection**: Fast-path extension check, fallback to first-chunk NUL check
- **Tree printer**: Requires O(N) memory to build hierarchy
## Security Considerations
```rust
const MAX_FILE_SIZE: u64 = 100 * 1024 * 1024; // Enforced before read
```
- Size check before open prevents processing massive files
- Streaming prevents OOM even for large allowed files (up to 100MB)
- No shell escape sequences in output (terminal-safe)
- Paths sanitized via Display trait
## Extension Points
- Syntax highlighting: Hook into markdown.rs, integrate syntect/bat
- Custom formats: Add variant to OutputFormat, implement new printer
- JSON output: Serialize WalkerEntry with file contents
- Pager integration: Detect TTY, pipe through less in print_file()