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// =============================================================================