# CLI Module
**Purpose**: Entry point orchestration — argument parsing, logging setup, output dispatch, and clipboard buffering.
## File Responsibilities
### args.rs
- **Clap derive definitions**: All CLI flags with validation and help text
- **OutputFormat enum**: String parsing (markdown/md/tree)
- **OutputMode enum**: Type-safe combination of `--clip` and `--suppress-stdout`
- **Getters**: Expose parsed values via `const fn` where possible
- **`to_cli_override()`**: Converts explicit CLI flags into `CliOverride` for config precedence
- **Defaults**: Markdown format, unlimited depth, respect gitignore
- **Logic mapping**: Uses `overrides_with` for `--dotfiles` / `--no-dotfiles` mutual exclusion
### buffer.rs
- **`buffer_entries_with_limit()`**: Markdown buffering with safe truncation and size limits
- **`buffer_tree_entries()`**: Tree buffering (batch render, all-or-nothing size gate)
- **`handle_clipboard_mode()`**: Top-level clipboard orchestration — buffers, writes stdout, copies clipboard
- **`MarkdownState`**: Tracks open code fences for rollback on size-limit truncation
- **`BufferResult`**: Carries buffered output, file counts, and whether the limit was hit
### clipboard.rs
- **`copy_to_clipboard()`**: Cross-platform clipboard write via arboard
- **Size guard**: Rejects content > 1 GB before attempting copy
- **Timeout**: 10 s deadline via a spawned thread + channel, prevents hangs on locked clipboards
- **Platform support**: X11/Wayland (Linux), NSPasteboard (macOS), Win32 (Windows)
### estimation.rs
- **`estimate_output_size()`**: O(1) pre-allocation hint based on file count
- **Conservative heuristic**: 1 536 bytes/file × 4/3 (markdown overhead buffer)
- **Overflow-safe**: Saturating arithmetic throughout
### run.rs
- **`run()`**: Main entry point — parses config, dispatches to file-list or directory-walk mode
- **Printer actor**: Bounded channel (cap 16) to a dedicated writer thread for contention-free stdout
- **`PrintMessage` enum**: `Block(String)` for markdown, `TreeEntry` for deferred tree rendering
- **`stream_to_stdout()`**: Common streaming path with backpressure
- **Panic propagation**: `join_writer()` resumes unwind instead of swallowing thread panics
### schema.rs
- **`generate_schema()`**: Emits JSON Schema for `luff.yaml` config files (for IDE autocomplete)
- **Uses crate error type**: Consistent with the rest of the codebase
### mod.rs
- Re-exports: `Args`, `Commands`, `OutputFormat`, `OutputMode`, `run`, `copy_to_clipboard`
## Output Modes
| (none) | `Stdout` | Stream to stdout (default) |
| `-c` | `Clipboard { show_stdout: true }` | Buffer → stdout AND clipboard |
| `-c -S` | `Clipboard { show_stdout: false }`| Buffer → clipboard only |
| `-S` | `Stdout` | No output (edge case, allowed) |
**Key Design**: Clipboard requires buffering the entire output (can't stream), so `-c` changes the execution strategy from streaming to collection.
## Ignore Logic
| (default) | `respect_gitignore=true` | Respects .gitignore |
| `--add` / `-a` | `respect_gitignore=false`| Ignores .gitignore (includes ignored files) |
| `--ignore <PATTERN>` | `ignore_globs` | Adds explicit glob patterns to exclude |
## Data Flow
```text
CLI args
→ Args::parse_args()
→ Config::from_args() (compiles globs, resolves root)
→ Walker (lazy iterator of WalkerItem)
↓
├─ Streaming mode (default)
│ Walker → bounded channel (cap 16) → writer thread → BufWriter<Stdout>
│ - Markdown: MarkdownPrinter::format_entry() → PrintMessage::Block
│ - Tree: PrintMessage::TreeEntry → TreePrinter (batch render on EOF)
│
└─ Clipboard mode (--clip)
Walker → buffer_entries_with_limit / buffer_tree_entries
→ BufferResult { output, processed, total_seen, size_exceeded }
→ stdout (if enabled) + clipboard copy
```
## Key Invariants
- `Args` is parsed exactly once at startup (`main.rs`)
- `run()` takes `&Args` (borrowing, not consuming)
- Clipboard failures print to stderr but don't return errors (graceful degradation)
- Streaming mode (default) has O(1) memory — files processed one at a time through the channel
- Buffered mode (clipboard) is O(n) with configurable size limits and safe truncation
- **SIGPIPE Handling**: Gracefully exits on broken pipe (e.g., `luff | head`)
- Writer thread panics are propagated, not swallowed
## Performance Notes
- Streaming mode: bounded channel provides backpressure; writer thread uses `BufWriter`
- Buffered mode: pre-allocates based on `estimate_output_size()`, truncates at safe markdown boundaries
- Clipboard write is a single operation (no chunking)
- Tree rendering is deferred until all paths are collected (inherently batch)
## Extension Points
- **New output format**: Add variant to `OutputFormat`, handle in `stream_to_stdout` and `buffer.rs` dispatch
- **Progress reporting**: Add a `PrintMessage::Progress` variant to the actor channel
- **Pager support**: Detect TTY, pipe through `less`/`bat` for large outputs