Skip to main content

stakpak_tui/app/
types.rs

1//! Type Definitions Module
2//!
3//! This module contains all type definitions used throughout the TUI application.
4//! Types are organized here for better maintainability and code organization.
5
6use crate::services::message::Message;
7use ratatui::text::Line;
8use std::collections::HashMap;
9use std::path::PathBuf;
10use std::sync::Arc;
11use uuid::Uuid;
12
13// Type alias to reduce complexity - now stores processed lines for better performance
14pub type MessageLinesCache = (Vec<Message>, usize, Vec<Line<'static>>);
15
16/// Cached rendered lines for a single message.
17/// Uses Arc to avoid expensive cloning when returning cached lines.
18#[derive(Clone, Debug)]
19pub struct RenderedMessageCache {
20    /// Hash of the message content for change detection
21    pub content_hash: u64,
22    /// The rendered lines for this message (shared via Arc to avoid cloning)
23    pub rendered_lines: Arc<Vec<Line<'static>>>,
24    /// Width the message was rendered at
25    pub width: usize,
26}
27
28/// Per-message cache for efficient incremental rendering.
29/// Only re-renders messages that have actually changed.
30pub type PerMessageCache = HashMap<Uuid, RenderedMessageCache>;
31
32/// Cache for the currently visible lines on screen.
33/// This avoids re-slicing and cloning on every frame when only scroll position changes.
34#[derive(Clone, Debug)]
35pub struct VisibleLinesCache {
36    /// The scroll position these lines were computed for
37    pub scroll: usize,
38    /// The width these lines were computed for
39    pub width: usize,
40    /// The height (number of lines) requested
41    pub height: usize,
42    /// The visible lines (Arc to avoid cloning on every frame)
43    pub lines: Arc<Vec<Line<'static>>>,
44    /// Generation counter from assembled cache (to detect when source changed)
45    pub source_generation: u64,
46}
47
48/// Performance metrics for render operations (for benchmarking)
49#[derive(Debug, Default, Clone)]
50pub struct RenderMetrics {
51    /// Total time spent rendering in the last render cycle (microseconds)
52    pub last_render_time_us: u64,
53    /// Number of messages that hit the cache
54    pub cache_hits: usize,
55    /// Number of messages that missed the cache and required re-rendering
56    pub cache_misses: usize,
57    /// Total number of lines rendered
58    pub total_lines: usize,
59    /// Rolling average render time (microseconds)
60    pub avg_render_time_us: u64,
61    /// Number of render cycles tracked for average
62    render_count: u64,
63}
64
65impl RenderMetrics {
66    pub fn new() -> Self {
67        Self::default()
68    }
69
70    /// Record a new render cycle's metrics
71    pub fn record_render(
72        &mut self,
73        render_time_us: u64,
74        cache_hits: usize,
75        cache_misses: usize,
76        total_lines: usize,
77    ) {
78        self.last_render_time_us = render_time_us;
79        self.cache_hits = cache_hits;
80        self.cache_misses = cache_misses;
81        self.total_lines = total_lines;
82
83        // Update rolling average
84        self.render_count += 1;
85        if self.render_count == 1 {
86            self.avg_render_time_us = render_time_us;
87        } else {
88            // Exponential moving average with alpha = 0.1
89            self.avg_render_time_us = (self.avg_render_time_us * 9 + render_time_us) / 10;
90        }
91    }
92
93    /// Reset metrics (useful for benchmarking specific scenarios)
94    pub fn reset(&mut self) {
95        *self = Self::default();
96    }
97}
98
99/// Async file_search result struct
100pub struct FileSearchResult {
101    pub filtered_helpers: Vec<HelperCommand>,
102    pub filtered_files: Vec<String>,
103    pub cursor_position: usize,
104    pub input: String,
105}
106
107#[derive(Debug, Clone)]
108pub struct HelperCommand {
109    pub command: &'static str,
110    pub description: &'static str,
111}
112
113#[derive(Debug, Clone)]
114pub struct AttachedImage {
115    pub placeholder: String,
116    pub path: PathBuf,
117    pub filename: String,
118    pub dimensions: (u32, u32),
119    pub start_pos: usize,
120    pub end_pos: usize,
121}
122
123#[derive(Debug)]
124pub struct SessionInfo {
125    pub title: String,
126    pub id: String,
127    pub updated_at: String,
128    pub checkpoints: Vec<String>,
129}
130
131#[derive(Debug, PartialEq)]
132pub enum LoadingType {
133    Llm,
134    Sessions,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Hash)]
138pub enum LoadingOperation {
139    LlmRequest,
140    ToolExecution,
141    SessionsList,
142    StreamProcessing,
143    LocalContext,
144    Rulebooks,
145    CheckpointResume,
146}
147
148#[derive(Debug, Clone, PartialEq)]
149pub enum ToolCallStatus {
150    Approved,
151    Rejected,
152    Executed,
153    Skipped,
154    Pending,
155}
156
157/// Mode for the unified shortcuts/commands/sessions popup
158#[derive(Debug, Clone, Copy, PartialEq, Default)]
159pub enum ShortcutsPopupMode {
160    #[default]
161    Commands,
162    Shortcuts,
163    Sessions,
164}
165
166#[derive(Debug)]
167pub struct LoadingStateManager {
168    active_operations: std::collections::HashSet<LoadingOperation>,
169}
170
171impl Default for LoadingStateManager {
172    fn default() -> Self {
173        Self::new()
174    }
175}
176
177impl LoadingStateManager {
178    pub fn new() -> Self {
179        Self {
180            active_operations: std::collections::HashSet::new(),
181        }
182    }
183
184    pub fn start_operation(&mut self, operation: LoadingOperation) {
185        self.active_operations.insert(operation);
186    }
187
188    pub fn end_operation(&mut self, operation: LoadingOperation) {
189        self.active_operations.remove(&operation);
190    }
191
192    pub fn is_loading(&self) -> bool {
193        !self.active_operations.is_empty()
194    }
195
196    pub fn get_loading_type(&self) -> LoadingType {
197        if self
198            .active_operations
199            .contains(&LoadingOperation::SessionsList)
200        {
201            LoadingType::Sessions
202        } else {
203            LoadingType::Llm
204        }
205    }
206
207    pub fn clear_all(&mut self) {
208        self.active_operations.clear();
209    }
210}