Skip to main content

mermaid_cli/tui/state/
conversation.rs

1/// Conversation state management
2///
3/// Handles chat messages, history, and persistence.
4
5use std::collections::VecDeque;
6
7use ratatui::text::Line;
8use rustc_hash::FxHashMap;
9
10use crate::context::Context;
11use crate::models::ChatMessage;
12use crate::session::{ConversationHistory, ConversationManager};
13
14/// Session state - conversation history and persistence
15pub struct ConversationState {
16    /// Current chat messages
17    pub messages: Vec<ChatMessage>,
18    /// Conversation manager for persistence
19    pub conversation_manager: Option<ConversationManager>,
20    /// Current conversation being tracked
21    pub current_conversation: Option<ConversationHistory>,
22    /// Input history for arrow key navigation (loaded from session)
23    pub input_history: VecDeque<String>,
24    /// Current position in history (None = editing current input, Some(i) = viewing history[i])
25    pub history_index: Option<usize>,
26    /// Saved input when navigating away from current draft
27    pub history_buffer: String,
28    /// Context for dynamic file tree reloading
29    pub context: Option<Context>,
30    /// Cumulative token count for the entire conversation
31    pub cumulative_tokens: usize,
32    /// Auto-generated conversation title (like Claude Code)
33    pub conversation_title: Option<String>,
34    /// Cached parsed markdown per message: (message_index, content_len) -> parsed lines
35    /// Invalidated when content length changes (cheap proxy for content change)
36    pub markdown_cache: FxHashMap<(usize, usize), Vec<Line<'static>>>,
37}
38
39impl ConversationState {
40    /// Create a new ConversationState with default values
41    pub fn new() -> Self {
42        Self {
43            messages: Vec::new(),
44            conversation_manager: None,
45            current_conversation: None,
46            input_history: VecDeque::new(),
47            history_index: None,
48            history_buffer: String::new(),
49            context: None,
50            cumulative_tokens: 0,
51            conversation_title: None,
52            markdown_cache: FxHashMap::default(),
53        }
54    }
55
56    /// Create ConversationState with conversation management
57    pub fn with_conversation(
58        conversation_manager: Option<ConversationManager>,
59        current_conversation: Option<ConversationHistory>,
60        input_history: VecDeque<String>,
61    ) -> Self {
62        Self {
63            messages: Vec::new(),
64            conversation_manager,
65            current_conversation,
66            input_history,
67            history_index: None,
68            history_buffer: String::new(),
69            context: None,
70            cumulative_tokens: 0,
71            conversation_title: None,
72            markdown_cache: FxHashMap::default(),
73        }
74    }
75
76    /// Add tokens to the cumulative count
77    pub fn add_tokens(&mut self, count: usize) {
78        self.cumulative_tokens += count;
79    }
80
81    /// Get message count
82    pub fn message_count(&self) -> usize {
83        self.messages.len()
84    }
85
86    /// Check if conversation is empty
87    pub fn is_empty(&self) -> bool {
88        self.messages.is_empty()
89    }
90}
91
92impl Default for ConversationState {
93    fn default() -> Self {
94        Self::new()
95    }
96}