1use std::{collections::VecDeque, sync::Arc, time::Instant};
2
3#[cfg(test)]
4use anstyle::Color as AnsiColorEnum;
5use anstyle::RgbColor;
6use ratatui::crossterm::event::{
7 Event as CrosstermEvent, KeyCode, KeyEvent, KeyEventKind, MouseEvent, MouseEventKind,
8};
9
10use ratatui::{
11 Frame,
12 layout::{Constraint, Layout, Rect},
13 text::{Line, Span, Text},
14 widgets::{Clear, ListState, Widget},
15};
16use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
17
18use super::{
19 style::{measure_text_width, ratatui_color_from_ansi, ratatui_style_from_inline},
20 types::{
21 InlineCommand, InlineEvent, InlineHeaderContext, InlineMessageKind, InlineTextStyle,
22 InlineTheme,
23 },
24};
25use crate::config::constants::ui;
26use crate::ui::tui::widgets::SessionWidget;
27
28pub mod file_palette;
29mod header;
30mod impl_events;
31mod impl_init;
32mod impl_input;
33mod impl_layout;
34mod impl_logs;
35mod impl_render;
36mod impl_scroll;
37mod impl_style;
38mod input;
39mod input_manager;
40mod message;
41pub mod modal;
42pub mod mouse_selection;
43mod navigation;
44mod palette_renderer;
45mod queue;
46pub mod render;
47mod scroll;
48pub mod slash;
49pub mod slash_palette;
50pub mod styling;
51mod text_utils;
52mod transcript;
53
54mod command;
56mod editing;
57
58pub mod config;
59mod diff_preview;
60mod events;
61pub mod history_picker;
62mod message_renderer;
63mod messages;
64mod palette;
65mod reflow;
66mod reverse_search;
67mod spinner;
68mod state;
69pub mod terminal_capabilities;
70mod terminal_title;
71#[cfg(test)]
72mod tests;
73mod tool_renderer;
74mod trust;
75
76use self::file_palette::FilePalette;
77use self::history_picker::HistoryPickerState;
78use self::input_manager::InputManager;
79use self::message::{MessageLabels, MessageLine};
80use self::modal::{ModalState, WizardModalState};
81
82use self::config::AppearanceConfig;
83pub(crate) use self::input::status_requires_shimmer;
84use self::mouse_selection::MouseSelectionState;
85use self::queue::QueueOverlay;
86use self::scroll::ScrollManager;
87use self::slash_palette::SlashPalette;
88use self::spinner::{ShimmerState, ThinkingSpinner};
89use self::styling::SessionStyles;
90use self::transcript::TranscriptReflowCache;
91#[cfg(test)]
92use super::types::InlineHeaderHighlight;
93use crate::ui::tui::log::{LogEntry, highlight_log_entry};
95
96const USER_PREFIX: &str = "";
97const PLACEHOLDER_COLOR: RgbColor =
98 RgbColor(ui::PLACEHOLDER_R, ui::PLACEHOLDER_G, ui::PLACEHOLDER_B);
99const MAX_LOG_LINES: usize = 256;
100const MAX_LOG_DRAIN_PER_TICK: usize = 256;
101
102#[derive(Clone, Debug)]
103struct CollapsedPaste {
104 line_index: usize,
105 full_text: String,
106}
107
108pub struct Session {
109 pub(crate) input_manager: InputManager,
112 pub(crate) scroll_manager: ScrollManager,
114 user_scrolled: bool,
115
116 pub(crate) lines: Vec<MessageLine>,
118 collapsed_pastes: Vec<CollapsedPaste>,
119 pub(crate) theme: InlineTheme,
120 pub(crate) styles: SessionStyles,
121 pub(crate) appearance: AppearanceConfig,
122 pub(crate) header_context: InlineHeaderContext,
123 pub(crate) header_rows: u16,
124 pub(crate) labels: MessageLabels,
125
126 prompt_prefix: String,
128 prompt_style: InlineTextStyle,
129 placeholder: Option<String>,
130 placeholder_style: Option<InlineTextStyle>,
131 pub(crate) input_status_left: Option<String>,
132 pub(crate) input_status_right: Option<String>,
133 input_compact_mode: bool,
134
135 slash_palette: SlashPalette,
137 #[allow(dead_code)]
138 navigation_state: ListState,
139 input_enabled: bool,
140 cursor_visible: bool,
141 pub(crate) needs_redraw: bool,
142 pub(crate) needs_full_clear: bool,
143 pub(crate) transcript_content_changed: bool,
145 should_exit: bool,
146 scroll_cursor_steady_until: Option<Instant>,
147 last_shimmer_active: bool,
148 pub(crate) view_rows: u16,
149 pub(crate) input_height: u16,
150 pub(crate) transcript_rows: u16,
151 pub(crate) transcript_width: u16,
152 pub(crate) transcript_view_top: usize,
153 transcript_area: Option<Rect>,
154 input_area: Option<Rect>,
155
156 log_receiver: Option<UnboundedReceiver<LogEntry>>,
158 log_lines: VecDeque<Arc<Text<'static>>>,
159 log_cached_text: Option<Arc<Text<'static>>>,
160 log_evicted: bool,
161 pub(crate) show_logs: bool,
162
163 transcript_cache: Option<TranscriptReflowCache>,
165 pub(crate) visible_lines_cache: Option<(usize, u16, Arc<Vec<Line<'static>>>)>,
168 pub(crate) queued_inputs: Vec<String>,
169 queue_overlay_cache: Option<QueueOverlay>,
170 queue_overlay_version: u64,
171 pub(crate) modal: Option<ModalState>,
172 wizard_modal: Option<WizardModalState>,
173 line_revision_counter: u64,
174 first_dirty_line: Option<usize>,
176 in_tool_code_fence: bool,
177
178 pub(crate) file_palette: Option<FilePalette>,
180 pub(crate) file_palette_active: bool,
181
182 pub(crate) thinking_spinner: ThinkingSpinner,
184 pub(crate) shimmer_state: ShimmerState,
185
186 pub(crate) reverse_search_state: crate::ui::tui::session::reverse_search::ReverseSearchState,
188
189 pub(crate) history_picker_state: HistoryPickerState,
191
192 pub(crate) active_pty_sessions: Option<Arc<std::sync::atomic::AtomicUsize>>,
194
195 #[allow(dead_code)]
197 pub(crate) clipboard: String,
198
199 pub(crate) mouse_selection: MouseSelectionState,
201
202 pub(crate) diff_preview: Option<crate::ui::tui::types::DiffPreviewState>,
204
205 pub(crate) skip_confirmations: bool,
206
207 pub(crate) header_lines_cache: Option<Vec<Line<'static>>>,
209 pub(crate) header_height_cache: std::collections::HashMap<u16, u16>,
210 pub(crate) queued_inputs_preview_cache: Option<Vec<String>>,
211
212 pub(crate) app_name: String,
215 pub(crate) workspace_root: Option<std::path::PathBuf>,
217 last_terminal_title: Option<String>,
219}