koda_cli/tui_types.rs
1//! TUI type definitions — enums, type aliases, and constants.
2//!
3//! Extracted from `tui_app.rs` to keep type definitions separate
4//! from the event loop logic. See #209.
5
6use ratatui::{Terminal, backend::CrosstermBackend};
7
8/// Ratatui terminal backed by stdout.
9pub(crate) type Term = Terminal<CrosstermBackend<std::io::Stdout>>;
10
11// Viewport height constants removed — fullscreen mode (#472)
12
13// ── Type aliases for dropdown menus ─────────────────────────
14
15pub(crate) type SlashDropdown =
16 crate::widgets::dropdown::DropdownState<crate::widgets::slash_menu::SlashCommand>;
17pub(crate) type ModelDropdown =
18 crate::widgets::dropdown::DropdownState<crate::widgets::model_menu::ModelItem>;
19pub(crate) type ProviderDropdown =
20 crate::widgets::dropdown::DropdownState<crate::widgets::provider_menu::ProviderItem>;
21pub(crate) type SessionDropdown =
22 crate::widgets::dropdown::DropdownState<crate::widgets::session_menu::SessionItem>;
23pub(crate) type FileDropdown =
24 crate::widgets::dropdown::DropdownState<crate::widgets::file_menu::FileItem>;
25
26// ── Session state ────────────────────────────────────────────
27
28/// What the TUI is currently doing.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub(crate) enum TuiState {
31 /// Waiting for user input (no inference running).
32 Idle,
33 /// An inference turn is running.
34 Inferring,
35}
36
37/// What's currently shown in the `menu_area` below the status bar.
38/// Only one menu can be active at a time.
39pub enum MenuContent {
40 /// Nothing — menu_area is empty.
41 None,
42 /// Slash command dropdown (auto-appears on `/`).
43 Slash(SlashDropdown),
44 /// Model picker dropdown (`/model` with no args).
45 Model(ModelDropdown),
46 /// Provider picker dropdown (`/provider` with no args).
47 Provider(ProviderDropdown),
48 /// Provider model list — second step of `/provider` (pick provider → list its models).
49 ProviderModels(ModelDropdown, koda_core::config::ProviderType),
50 /// Key management — pick a provider to set its API key (`/key`).
51 Key(ProviderDropdown),
52 /// Session picker dropdown (`/sessions` with no args).
53 Session(SessionDropdown),
54 /// File picker dropdown (auto-appears on `@`).
55 File {
56 dropdown: FileDropdown,
57 /// Text before the `@` token (to reconstruct the full input).
58 prefix: String,
59 },
60 /// Wizard trail — completed steps shown dimmed during multi-step flow.
61 WizardTrail(Vec<(String, String)>),
62 /// Approval hotkey bar — shown during inference when engine requests approval.
63 Approval {
64 id: String,
65 tool_name: String,
66 detail: String,
67 },
68 /// AskUser input bar — model is asking a clarifying question.
69 AskUser {
70 id: String,
71 question: String,
72 options: Vec<String>,
73 },
74 /// Loop cap hotkey bar — continue or stop after iteration limit.
75 LoopCap,
76 /// Purge confirmation bar — \[y\] confirm / \[n\] cancel.
77 PurgeConfirm { min_age_days: u32, detail: String },
78 /// Ctrl+R reverse history search overlay.
79 HistorySearch {
80 /// Current search query.
81 query: String,
82 /// Matching history entries, newest first (pre-computed on each keystroke).
83 matches: Vec<String>,
84 /// Index into `matches` of the highlighted row.
85 selected: usize,
86 },
87}
88
89impl MenuContent {
90 pub(crate) fn is_none(&self) -> bool {
91 matches!(self, MenuContent::None)
92 }
93}
94
95/// What the prompt input area is currently doing.
96/// Normally it's chat input. During wizard flows, it's repurposed
97/// for text input (API key, URL, etc.).
98#[derive(Clone)]
99pub(crate) enum PromptMode {
100 /// Normal chat input: ⚡> █
101 Chat,
102 /// Wizard text input: label: █
103 WizardInput { label: String },
104}
105
106/// Provider setup wizard state machine.
107/// Each variant holds the data collected so far.
108pub(crate) enum ProviderWizard {
109 /// Step 1: provider selected, now need API key (or URL for local providers).
110 ApiKey {
111 provider_type: koda_core::config::ProviderType,
112 base_url: String,
113 env_name: String,
114 },
115 /// Key-only mode from `/key` — set key and return, no model list.
116 ApiKeyOnly { env_name: String },
117 /// Step 1 (local): provider selected, now need URL.
118 Url {
119 provider_type: koda_core::config::ProviderType,
120 },
121}