Skip to main content

reovim_kernel/api/module/
registration.rs

1//! Registration types for commands, keybindings, and event handlers.
2
3use {super::RegistrationFlags, crate::core::CommandId};
4
5/// Bit position for "accepts count" capability.
6const CAP_ACCEPTS_COUNT: u8 = 1 << 0;
7/// Bit position for "accepts motion" capability.
8const CAP_ACCEPTS_MOTION: u8 = 1 << 1;
9/// Bit position for "is jump" capability.
10const CAP_IS_JUMP: u8 = 1 << 2;
11/// Bit position for "is text-modifying" capability.
12const CAP_IS_TEXT_MODIFYING: u8 = 1 << 3;
13
14/// Command registration descriptor.
15///
16/// Linux equivalent: Like `struct file_operations` - declares command capabilities.
17///
18/// Fields align with `CommandTrait` from the original design (see [`archive/pre_kernel/lib/core/src/command/traits.rs`](https://github.com/ds1sqe/reovim/blob/81806439/archive/pre_kernel/lib/core/src/command/traits.rs)).
19///
20/// Command capabilities (accepts count, accepts motion, is jump, is text-modifying)
21/// are stored as a `u8` bitfield to preserve kernel purity (zero external deps).
22#[derive(Debug, Clone)]
23pub struct CommandRegistration {
24    /// Unique command identifier (e.g., "delete", "yank", "motion:word").
25    pub id: &'static str,
26    /// Human-readable name for help display.
27    pub name: &'static str,
28    /// Description for help system.
29    pub description: &'static str,
30    /// Category for help grouping (e.g., "motion", "operator", "edit").
31    pub category: Option<&'static str>,
32    /// Command capability flags (`accepts_count`, `accepts_motion`, `is_jump`, `is_text_modifying`).
33    capabilities: u8,
34    /// Dependencies on other commands (Linux: module dependencies).
35    pub depends_on: &'static [&'static str],
36    /// Registration flags.
37    pub flags: RegistrationFlags,
38}
39
40impl CommandRegistration {
41    /// Create a new command registration with required id.
42    #[must_use]
43    pub const fn new(id: &'static str) -> Self {
44        Self {
45            id,
46            name: "",
47            description: "",
48            category: None,
49            capabilities: 0,
50            depends_on: &[],
51            flags: RegistrationFlags::new(),
52        }
53    }
54
55    /// Set the display name.
56    #[must_use]
57    pub const fn with_name(mut self, name: &'static str) -> Self {
58        self.name = name;
59        self
60    }
61
62    /// Set the description.
63    #[must_use]
64    pub const fn with_description(mut self, desc: &'static str) -> Self {
65        self.description = desc;
66        self
67    }
68
69    /// Set the category.
70    #[must_use]
71    pub const fn with_category(mut self, cat: &'static str) -> Self {
72        self.category = Some(cat);
73        self
74    }
75
76    /// Mark command as accepting a count.
77    #[must_use]
78    pub const fn with_count(mut self) -> Self {
79        self.capabilities |= CAP_ACCEPTS_COUNT;
80        self
81    }
82
83    /// Mark command as accepting a motion.
84    #[must_use]
85    pub const fn with_motion(mut self) -> Self {
86        self.capabilities |= CAP_ACCEPTS_MOTION;
87        self
88    }
89
90    /// Mark command as a jump.
91    #[must_use]
92    pub const fn with_jump(mut self) -> Self {
93        self.capabilities |= CAP_IS_JUMP;
94        self
95    }
96
97    /// Mark command as text-modifying.
98    #[must_use]
99    pub const fn with_text_modifying(mut self) -> Self {
100        self.capabilities |= CAP_IS_TEXT_MODIFYING;
101        self
102    }
103
104    /// Set dependencies.
105    #[must_use]
106    pub const fn with_depends_on(mut self, deps: &'static [&'static str]) -> Self {
107        self.depends_on = deps;
108        self
109    }
110
111    /// Set registration flags.
112    #[must_use]
113    pub const fn with_flags(mut self, flags: RegistrationFlags) -> Self {
114        self.flags = flags;
115        self
116    }
117
118    // ========================================================================
119    // Query Methods
120    // ========================================================================
121
122    /// Check if this command accepts a count prefix (e.g., 5j).
123    #[must_use]
124    pub const fn accepts_count(&self) -> bool {
125        self.capabilities & CAP_ACCEPTS_COUNT != 0
126    }
127
128    /// Check if this command accepts a motion (e.g., dw, c$).
129    #[must_use]
130    pub const fn accepts_motion(&self) -> bool {
131        self.capabilities & CAP_ACCEPTS_MOTION != 0
132    }
133
134    /// Check if this command is a "jump" (recorded in jump list).
135    #[must_use]
136    pub const fn is_jump(&self) -> bool {
137        self.capabilities & CAP_IS_JUMP != 0
138    }
139
140    /// Check if this command modifies buffer text (for undo grouping).
141    #[must_use]
142    pub const fn is_text_modifying(&self) -> bool {
143        self.capabilities & CAP_IS_TEXT_MODIFYING != 0
144    }
145}
146
147/// Keybinding registration descriptor.
148///
149/// Linux equivalent: Like `struct input_device_id` - declares key matching.
150#[derive(Debug, Clone)]
151pub struct KeybindingRegistration {
152    /// Key sequence in vim notation (e.g., `"dd"`, `"<C-w>h"`, `"<Space>ff"`).
153    pub keys: &'static str,
154    /// Command ID to invoke (compile-time verified).
155    pub command_id: CommandId,
156    /// Modes where binding is active (e.g., `&["normal"]`, `&["normal", "visual"]`).
157    /// Empty slice means all modes (like Linux's match-all).
158    pub modes: &'static [&'static str],
159    /// Description for which-key / help.
160    pub description: &'static str,
161    /// Category for which-key grouping (e.g., "window", "file", "search").
162    pub category: Option<&'static str>,
163    /// Whether binding is enabled (for conditional keybindings).
164    pub enabled: bool,
165    /// Priority for conflict resolution (lower = higher priority).
166    /// Like Linux driver priority for matching.
167    pub priority: u32,
168    /// Dependencies on other keybindings or commands.
169    pub depends_on: &'static [&'static str],
170    /// Registration flags.
171    pub flags: RegistrationFlags,
172}
173
174impl KeybindingRegistration {
175    /// Create a new keybinding registration.
176    ///
177    /// The `command_id` parameter is a typed `CommandId`, enabling compile-time
178    /// verification that the referenced command exists. Import command ID constants
179    /// from the appropriate module (e.g., `reovim_module_editor::ids::CURSOR_DOWN`).
180    #[must_use]
181    pub const fn new(keys: &'static str, command_id: CommandId) -> Self {
182        Self {
183            keys,
184            command_id,
185            modes: &[],
186            description: "",
187            category: None,
188            enabled: true,
189            priority: 100, // Default plugin priority
190            depends_on: &[],
191            flags: RegistrationFlags::new(),
192        }
193    }
194
195    /// Set active modes.
196    #[must_use]
197    pub const fn with_modes(mut self, modes: &'static [&'static str]) -> Self {
198        self.modes = modes;
199        self
200    }
201
202    /// Set description.
203    #[must_use]
204    pub const fn with_description(mut self, desc: &'static str) -> Self {
205        self.description = desc;
206        self
207    }
208
209    /// Set category.
210    #[must_use]
211    pub const fn with_category(mut self, cat: &'static str) -> Self {
212        self.category = Some(cat);
213        self
214    }
215
216    /// Disable the keybinding.
217    #[must_use]
218    pub const fn with_disabled(mut self) -> Self {
219        self.enabled = false;
220        self
221    }
222
223    /// Set priority.
224    #[must_use]
225    pub const fn with_priority(mut self, priority: u32) -> Self {
226        self.priority = priority;
227        self
228    }
229
230    /// Set dependencies.
231    #[must_use]
232    pub const fn with_depends_on(mut self, deps: &'static [&'static str]) -> Self {
233        self.depends_on = deps;
234        self
235    }
236
237    /// Set registration flags.
238    #[must_use]
239    pub const fn with_flags(mut self, flags: RegistrationFlags) -> Self {
240        self.flags = flags;
241        self
242    }
243}
244
245/// Event handler registration descriptor.
246///
247/// Linux equivalent: Like `struct notifier_block` - declares event subscription.
248///
249/// Priority convention (from EventBus):
250/// - 0-50: Core handlers (kernel-level)
251/// - 100: Default plugin priority
252/// - 200+: Cleanup/late handlers
253#[derive(Debug, Clone)]
254pub struct EventHandlerRegistration {
255    /// Event type name (e.g., `BufferChanged`, `CursorMoved`).
256    pub event_type: &'static str,
257    /// Handler priority (lower = called earlier).
258    pub priority: u32,
259    /// Description for debugging/introspection.
260    pub description: &'static str,
261    /// Whether handler auto-unsubscribes after one event (one-shot).
262    pub once: bool,
263    /// Optional target component ID for scoped events.
264    pub target_component: Option<&'static str>,
265    /// Dependencies on other handlers or modules.
266    pub depends_on: &'static [&'static str],
267    /// Registration flags.
268    pub flags: RegistrationFlags,
269}
270
271impl EventHandlerRegistration {
272    /// Create a new event handler registration.
273    #[must_use]
274    pub const fn new(event_type: &'static str) -> Self {
275        Self {
276            event_type,
277            priority: 100, // Default plugin priority
278            description: "",
279            once: false,
280            target_component: None,
281            depends_on: &[],
282            flags: RegistrationFlags::new(),
283        }
284    }
285
286    /// Set priority.
287    #[must_use]
288    pub const fn with_priority(mut self, priority: u32) -> Self {
289        self.priority = priority;
290        self
291    }
292
293    /// Set description.
294    #[must_use]
295    pub const fn with_description(mut self, desc: &'static str) -> Self {
296        self.description = desc;
297        self
298    }
299
300    /// Mark as one-shot handler.
301    #[must_use]
302    pub const fn with_once(mut self) -> Self {
303        self.once = true;
304        self
305    }
306
307    /// Set target component.
308    #[must_use]
309    pub const fn with_target(mut self, component: &'static str) -> Self {
310        self.target_component = Some(component);
311        self
312    }
313
314    /// Set dependencies.
315    #[must_use]
316    pub const fn with_depends_on(mut self, deps: &'static [&'static str]) -> Self {
317        self.depends_on = deps;
318        self
319    }
320
321    /// Set registration flags.
322    #[must_use]
323    pub const fn with_flags(mut self, flags: RegistrationFlags) -> Self {
324        self.flags = flags;
325        self
326    }
327
328    /// Set core priority (clamped to 0-50 range).
329    #[must_use]
330    pub const fn core_priority(mut self, priority: u32) -> Self {
331        self.priority = if priority > 50 { 50 } else { priority };
332        self
333    }
334}