flywheel/actor/messages.rs
1//! Message types for actor communication.
2//!
3//! These enums define the protocol between actors in the system.
4
5use std::time::Instant;
6use crate::buffer::Buffer;
7
8/// Key codes for keyboard input.
9///
10/// This is a simplified subset of crossterm's `KeyCode`, designed
11/// for the needs of agentic CLIs.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
13pub enum KeyCode {
14 /// A printable character.
15 Char(char),
16 /// Function key (F1-F12).
17 F(u8),
18 /// Backspace key.
19 Backspace,
20 /// Enter/Return key.
21 Enter,
22 /// Left arrow.
23 Left,
24 /// Right arrow.
25 Right,
26 /// Up arrow.
27 Up,
28 /// Down arrow.
29 Down,
30 /// Home key.
31 Home,
32 /// End key.
33 End,
34 /// Page Up.
35 PageUp,
36 /// Page Down.
37 PageDown,
38 /// Tab key.
39 Tab,
40 /// Backtab (Shift+Tab).
41 BackTab,
42 /// Delete key.
43 Delete,
44 /// Insert key.
45 Insert,
46 /// Escape key.
47 Esc,
48 /// Null (Ctrl+Space on some terminals).
49 Null,
50}
51
52/// Key modifiers.
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
54#[allow(clippy::struct_excessive_bools)]
55pub struct KeyModifiers {
56 /// Shift key held.
57 pub shift: bool,
58 /// Control key held.
59 pub control: bool,
60 /// Alt/Option key held.
61 pub alt: bool,
62 /// Super/Command/Windows key held.
63 pub super_key: bool,
64}
65
66impl KeyModifiers {
67 /// No modifiers.
68 pub const NONE: Self = Self {
69 shift: false,
70 control: false,
71 alt: false,
72 super_key: false,
73 };
74
75 /// Check if any modifier is active.
76 pub const fn any(&self) -> bool {
77 self.shift || self.control || self.alt || self.super_key
78 }
79}
80
81/// Mouse button.
82#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
83pub enum MouseButton {
84 /// Left mouse button.
85 Left,
86 /// Right mouse button.
87 Right,
88 /// Middle mouse button.
89 Middle,
90}
91
92/// Mouse event details.
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub struct MouseEvent {
95 /// X coordinate (column).
96 pub x: u16,
97 /// Y coordinate (row).
98 pub y: u16,
99 /// Mouse button involved (if any).
100 pub button: Option<MouseButton>,
101 /// Key modifiers held during mouse event.
102 pub modifiers: KeyModifiers,
103}
104
105/// Events from the input thread.
106///
107/// These are sent from the input actor to the main loop.
108#[derive(Debug, Clone)]
109pub enum InputEvent {
110 /// A key was pressed.
111 Key {
112 /// The key code.
113 code: KeyCode,
114 /// Modifiers held during keypress.
115 modifiers: KeyModifiers,
116 },
117
118 /// Mouse button pressed.
119 MouseDown(MouseEvent),
120
121 /// Mouse button released.
122 MouseUp(MouseEvent),
123
124 /// Mouse moved (only if tracking enabled).
125 MouseMove(MouseEvent),
126
127 /// Mouse scroll.
128 MouseScroll {
129 /// X coordinate.
130 x: u16,
131 /// Y coordinate.
132 y: u16,
133 /// Scroll delta (positive = up, negative = down).
134 delta: i16,
135 },
136
137 /// Terminal was resized.
138 Resize {
139 /// New width in columns.
140 width: u16,
141 /// New height in rows.
142 height: u16,
143 },
144
145 /// Focus gained.
146 FocusGained,
147
148 /// Focus lost.
149 FocusLost,
150
151 /// Paste event (bracketed paste).
152 Paste(String),
153
154 /// Input thread encountered an error.
155 Error(String),
156
157 /// Input thread is shutting down.
158 Shutdown,
159}
160
161/// Commands sent to the render thread.
162#[derive(Debug)]
163pub enum RenderCommand {
164 /// Request a full redraw with new buffer content.
165 FullRedraw(Box<Buffer>),
166
167 /// Request a diff-based update.
168 /// Request a diff-based update with new buffer content.
169 Update(Box<Buffer>),
170
171 /// Resize the buffers.
172 Resize {
173 /// New width.
174 width: u16,
175 /// New height.
176 height: u16,
177 },
178
179 /// Set the cursor position and visibility.
180 SetCursor {
181 /// X position (None = hide cursor).
182 x: Option<u16>,
183 /// Y position.
184 y: u16,
185 },
186
187 /// Write raw bytes directly to the terminal output.
188 ///
189 /// This is used for the "Fast Path" optimization: directly writing generated
190 /// ANSI sequences without going through the diffing engine.
191 ///
192 /// **Warning**: The caller is responsible for ensuring these bytes do not
193 /// corrupt the terminal state or contradict the buffer state.
194 RawOutput {
195 /// The raw bytes to write.
196 bytes: Vec<u8>,
197 },
198
199 /// Shutdown the render thread.
200 Shutdown,
201}
202
203/// Events from agent/network threads.
204///
205/// These represent async data arriving from external sources.
206#[derive(Debug, Clone)]
207pub enum AgentEvent {
208 /// Token(s) received from agent stream.
209 Tokens {
210 /// The text content.
211 content: String,
212 /// Source identifier (for multi-agent scenarios).
213 source_id: u32,
214 /// Whether this is the final chunk.
215 is_final: bool,
216 },
217
218 /// Agent started a new response.
219 ResponseStart {
220 /// Source identifier.
221 source_id: u32,
222 },
223
224 /// Agent finished responding.
225 ResponseEnd {
226 /// Source identifier.
227 source_id: u32,
228 },
229
230 /// Agent encountered an error.
231 Error {
232 /// Error message.
233 message: String,
234 /// Source identifier.
235 source_id: u32,
236 },
237
238 /// Connection status changed.
239 ConnectionStatus {
240 /// Whether connected.
241 connected: bool,
242 /// Source identifier.
243 source_id: u32,
244 },
245}
246
247/// Frame timing information.
248#[derive(Debug, Clone)]
249#[allow(dead_code)]
250pub struct FrameInfo {
251 /// Frame number since engine start.
252 pub frame_number: u64,
253 /// Time when this frame started.
254 pub frame_start: Instant,
255 /// Duration of the previous frame's render.
256 pub last_render_time: std::time::Duration,
257 /// Current FPS (smoothed).
258 pub fps: f32,
259}
260
261impl Default for FrameInfo {
262 fn default() -> Self {
263 Self {
264 frame_number: 0,
265 frame_start: Instant::now(),
266 last_render_time: std::time::Duration::ZERO,
267 fps: 0.0,
268 }
269 }
270}