romm-cli 0.38.0

Rust-based CLI and TUI for the ROMM API
Documentation
# TUI internals (ratatui + crossterm)

This document explains how the terminal UI is wired together.

## Event loop

The heart of the TUI lives in `tui::app::App::run`:

- Enable raw mode
- Enter the alternate screen
- In a loop:
  - drain background tasks via `App::poll_background_tasks` (library metadata refresh completions)
  - draw the current screen via `App::render`
  - poll for key events with a short timeout
  - dispatch keys to the appropriate `handle_*` method
  - perform deferred work (like ROM loading)

## Library startup (metadata snapshot)

Choosing **Library** from the main menu loads a compact on-disk snapshot of platforms and merged collections (if present) so the list can render without waiting for the network. A background task then refetches the same endpoints, updates the UI when complete, and writes a fresh snapshot. Full ROM lists are still loaded on demand (and use the ROM list cache). Snapshot path defaults next to `ROMM_CACHE_PATH`; override with `ROMM_LIBRARY_METADATA_SNAPSHOT_PATH`.

The TUI uses `crossterm` to manage the terminal and `ratatui` to build widgets.

## Screens

Each screen is its own struct under `src/tui/screens/`:

- `MainMenuScreen` – entry menu
- `LibraryBrowseScreen` – consoles/collections + ROM list
- `SearchScreen` – text input + results table
- `GameDetailScreen` – detail view for a single ROM
- `DownloadScreen` – overlay showing downloads
- `SettingsScreen` – current config summary
- `SetupWizard` – first-run / reconnect configuration flow

The `AppScreen` enum in `tui::app` wraps these screen structs so that `App` only ever has one active screen at a time. During startup, a `StartupSplash` overlay (`screens/connected_splash`) may render before the main menu appears.

## App module layout

The TUI state machine lives under `src/tui/app/` (not a single file):

- `mod.rs``App`, `AppScreen`, `App::new`, key dispatch (`handle_key_event`), shortcut guards
- `run.rs` — terminal event loop (`App::run`)
- `render.rs` — frame drawing and global overlays (errors, update prompt)
- `background/` — async task completion types and spawn/poll helpers (`poll_background_tasks`)
- `handlers/` — one module per screen group (`library.rs`, `settings.rs`, …)
- `rom_load.rs` — ROM list fetch and collection prefetch scheduling
- `tests.rs` — unit tests for app behavior

Public exports are unchanged: `romm_cli::tui::app::{App, AppScreen}`.

## Theming

The TUI uses [ratatui-themekit](https://docs.rs/ratatui-themekit) preset palettes via `tui::theme::RommStyles`. `App` holds a resolved theme (`Box<dyn Theme>`) loaded from `config.json` (`theme` field, default `terminal`) or `ROMM_THEME`.

- **Settings → Appearance** — cycle presets with ←/→; live preview; **S** saves to `config.json`.
- **`terminal`** — ANSI named colors (widest terminal compatibility).
- **RGB presets** (Dracula, Nord, Tokyo Night, …) — need a truecolor-capable terminal (Windows Terminal, iTerm2, Alacritty, etc.).
- **`NO_COLOR=1`** — disables styling (no-color preset).

Semantic roles (`selection`, `label`, `success`, `error`, `warning`, `muted`) map to theme slots in `src/tui/theme.rs`. Screen renderers take `&RommStyles` instead of hardcoded colors.

## Layout and scrolling

`ratatui::layout::Layout` is used extensively to divide the terminal into smaller `Rect`s:

- A typical pattern is a vertical split into `main area + footer`.
- Complex screens (like the library browser) then split the main area
  horizontally into left/right panes.

Scrolling is done manually:

- For library/search results:
  - a `scroll_offset` index tracks which row is at the top
  - `visible` rows are computed dynamically from the available height
  - helper methods ensure the selected row stays inside the viewport