Skip to main content

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}