Krolyxon
Commit b139f20

rmptui.githubcopilot-instructions.md

68 lines · 3.6 KB · Markdown

1# Contributor and agent instructions for rmptui
2
3## Build, test, and lint
4
5- `cargo build` — compile the application.
6- `cargo run -- --config FILE` — run with a specific config (MPD at
7 `127.0.0.1:6600` by default; `MPD_HOST`/`MPD_PORT` override it).
8- `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test`.
9- `cargo test mpd::protocol` — run the tests of one module; `tests/mpd_client.rs`
10 exercises the client against a scripted fake MPD server.
11
12## Architecture
13
14- `mpd/` is a self-contained MPD client.
15 - `protocol.rs`: pure command encoding (every argument quoted and escaped)
16 and response parsing.
17 - `connection.rs`: async TCP and Unix-socket connections.
18 - `types.rs`: typed models.
19 - `commands.rs`: command constructors.
20 - `worker.rs`: two background tasks. The *idle* connection reports changed
21 subsystems. The *command* connection runs `Request`s from an `MpdHandle`
22 and answers `Query`s with `Reply`s. Both reconnect on their own.
23- `app.rs` owns the state and runs one `tokio::select!` loop over terminal
24 input, `AppEvent`s (MPD, lyrics, tag writes) and visualizer frames. UI code
25 never awaits MPD: it sends requests and reacts to the resulting events.
26- `state.rs` (`MpdState`) mirrors the server: status, current song, the queue
27 (updated incrementally via `plchanges`), stored playlists, and a database
28 version used to invalidate caches.
29- `screens/` holds one component per screen behind the `Screen` trait (`draw`,
30 `handle_action`, `on_mpd`, `on_enter`, `on_mouse`, `search`).
31 - Screens receive a `Ctx` with read access to config and state, the
32 `MpdHandle`, and an effect queue (`Effect`) for things only the app can do:
33 notifications, popups, tag writes, lyric reloads.
34 - Every screen sees every `MpdEvent`, so caches stay valid while hidden.
35- `popups/` holds modal components (`Popup` trait); the topmost popup gets all
36 keys. Destructive actions go through `ConfirmPopup`.
37- `ui/` holds the ncmpcpp-style frame (title row, progress bar, status line), the
38 virtualized searchable `ListView`, and the `LineInput` editor.
39- `config/`:
40 - `default.toml` is embedded and is the single source of truth for
41 defaults; user files are merged over it table by table.
42 - `keys.rs` parses key specs and builds the per-context `Keymap`.
43- `action.rs` defines the `Action`, `Context` and `ScreenId` enums. Each action
44 declares the contexts it may be bound in. Lookup order is: popup or screen
45 context → `navigation` → `global`.
46- `lyrics/`: LRC parser and the async lookup service (local `.lrc` → cache →
47 LRCLIB). `visualizer/`: fifo reader thread with FFT, plus bar smoothing.
48 `tags.rs`: lofty-based tag writing.
49
50## Conventions
51
52- Build MPD commands only through `mpd::commands` or `Command::arg`; never
53 format raw command strings from user data. Filter expressions go through
54 `protocol::filter_eq`/`filter_and`.
55- Prefer position-based commands (`move`, `delete`) for actions users repeat
56 quickly. They stay correct even when sent before the local queue refreshes.
57- Every new action needs:
58 - an `Action` variant with its contexts and description;
59 - a default binding in `config/default.toml` (a test enforces this);
60 - a README entry.
61- Every new option needs:
62 - a documented entry in `default.toml`;
63 - a field in the matching config struct (`deny_unknown_fields` catches
64 typos);
65 - validation in `Config::validate` if it has limits;
66 - README documentation.
67- Screens must not block: do file and network I/O in tasks (see lyrics) or
68 `spawn_blocking` (see tag writes) and report back through `AppEvent`.