Skip to main content

reovim_kernel/ipc/events/
key.rs

1//! Key press event for event-driven key dispatch.
2//!
3//! This event bridges the input driver and the runner's key handling
4//! system, enabling loosely-coupled key processing via `EventBus`.
5//!
6//! # Design Philosophy
7//!
8//! Following "mechanism, not policy":
9//! - `KeyPressEvent` is a pure data carrier (mechanism)
10//! - How keys are resolved is decided by handlers (policy in runner)
11//! - Session/client routing enables multi-session support
12//!
13//! # Example
14//!
15//! ```
16//! use reovim_kernel::api::v1::events::{KeyInput, KeyCode, Modifiers};
17//! use reovim_kernel::api::v1::events::key::{KeyPressEvent, SessionId, ClientId};
18//!
19//! let key = KeyInput {
20//!     key: KeyCode::Char('j'),
21//!     modifiers: Modifiers::NONE,
22//! };
23//!
24//! let event = KeyPressEvent::new(key, SessionId::new(0), ClientId::new(1));
25//! assert_eq!(event.session_id.as_usize(), 0);
26//! assert_eq!(event.client_id.as_usize(), 1);
27//! ```
28
29use crate::ipc::Event;
30
31use super::KeyInput;
32
33// =============================================================================
34// Session and Client Identifiers
35// =============================================================================
36
37/// Session identifier for event routing.
38///
39/// Represents a named editing session (like tmux sessions). Multiple clients
40/// can attach to the same session and share state.
41///
42/// This is a kernel-level mechanism type. The runner maps this to its
43/// internal session management.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct SessionId(usize);
46
47impl SessionId {
48    /// Create a new session ID.
49    #[must_use]
50    pub const fn new(id: usize) -> Self {
51        Self(id)
52    }
53
54    /// Get the raw ID value.
55    #[must_use]
56    pub const fn as_usize(&self) -> usize {
57        self.0
58    }
59}
60
61impl std::fmt::Display for SessionId {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        write!(f, "session-{}", self.0)
64    }
65}
66
67/// Client identifier for event routing.
68///
69/// Represents a connection to the server (like a tmux client). Each client
70/// has a unique ID within the server.
71///
72/// This is a kernel-level mechanism type. The runner maps this to its
73/// internal client/connection management.
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
75pub struct ClientId(usize);
76
77impl ClientId {
78    /// Create a new client ID.
79    #[must_use]
80    pub const fn new(id: usize) -> Self {
81        Self(id)
82    }
83
84    /// Get the raw ID value.
85    #[must_use]
86    pub const fn as_usize(&self) -> usize {
87        self.0
88    }
89}
90
91impl std::fmt::Display for ClientId {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        write!(f, "client-{}", self.0)
94    }
95}
96
97// =============================================================================
98// Key Press Event
99// =============================================================================
100
101/// Key press event emitted when a key is received.
102///
103/// This event is emitted by the runner's event loop and handled by
104/// registered key handlers. The handler performs key resolution
105/// and returns state changes via the result holder.
106///
107/// # Synchronous Processing
108///
109/// Key events are processed synchronously via `bus.emit()` because:
110/// - Key handling must complete before the next key is read
111/// - State mutations need to happen in order
112/// - Latency requirements demand immediate processing
113///
114/// # Session Routing
115///
116/// The `session_id` and `client_id` identify which session should
117/// process the key. Handlers filter events by session ID.
118///
119/// # Example
120///
121/// ```
122/// use reovim_kernel::api::v1::{EventBus, EventResult};
123/// use reovim_kernel::api::v1::events::{KeyInput, KeyCode, Modifiers, priority};
124/// use reovim_kernel::api::v1::events::key::{KeyPressEvent, SessionId, ClientId};
125///
126/// let bus = EventBus::new();
127///
128/// // Register handler for session 0
129/// let session_id = SessionId::new(0);
130/// let _sub = bus.subscribe::<KeyPressEvent, _>(priority::CORE, move |event| {
131///     if event.session_id != session_id {
132///         return EventResult::NotHandled;
133///     }
134///     // Process key...
135///     EventResult::Handled
136/// });
137///
138/// // Emit key event
139/// let key = KeyInput {
140///     key: KeyCode::Char('j'),
141///     modifiers: Modifiers::NONE,
142/// };
143/// bus.emit(KeyPressEvent::new(key, SessionId::new(0), ClientId::new(1)));
144/// ```
145#[derive(Debug, Clone, PartialEq, Eq)]
146pub struct KeyPressEvent {
147    /// The key input from the input driver.
148    pub key: KeyInput,
149    /// Session ID for routing.
150    pub session_id: SessionId,
151    /// Client ID that originated this key.
152    pub client_id: ClientId,
153}
154
155impl KeyPressEvent {
156    /// Create a new key press event.
157    #[must_use]
158    pub const fn new(key: KeyInput, session_id: SessionId, client_id: ClientId) -> Self {
159        Self {
160            key,
161            session_id,
162            client_id,
163        }
164    }
165
166    /// Get the event type name for logging.
167    #[must_use]
168    pub const fn event_type(&self) -> &'static str {
169        "KeyPressEvent"
170    }
171}
172
173impl Event for KeyPressEvent {}
174
175// =============================================================================