Skip to main content

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}