reovim_module_range_finder/
lib.rs1#![cfg_attr(coverage_nightly, allow(unused_features))]
2#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
3pub mod find_char;
20pub mod fold;
21pub mod jump;
22mod keybinding;
23
24use {
25 reovim_driver_input::{KeybindingStore, ModeInfo, ModeInfoStore, ResolverRegistry},
26 reovim_driver_manifest::ModeBridgeStore,
27 reovim_kernel::api::v1::{
28 CursorStyle, KeybindingRegistration, Module, ModuleContext, ModuleError, ModuleId,
29 ProbeResult, Version,
30 },
31};
32
33pub(crate) const KIND_JUMP: &str = "range-finder-jump";
34pub(crate) const KIND_FOLD: &str = "range-finder-fold";
35const MODULE_ID: ModuleId = ModuleId::new("range-finder");
36
37pub struct RangeFinderModule;
39
40impl RangeFinderModule {
41 #[must_use]
43 pub const fn new() -> Self {
44 Self
45 }
46}
47
48impl Default for RangeFinderModule {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl Module for RangeFinderModule {
55 fn id(&self) -> ModuleId {
56 MODULE_ID
57 }
58
59 fn name(&self) -> &'static str {
60 "range-finder"
61 }
62
63 fn version(&self) -> Version {
64 Version::new(0, 1, 0)
65 }
66
67 fn dependencies(&self) -> Vec<ModuleId> {
68 vec![]
69 }
70
71 fn optional_dependencies(&self) -> Vec<ModuleId> {
72 vec![ModuleId::new("vim")]
75 }
76
77 #[cfg_attr(coverage_nightly, coverage(off))]
78 fn init(&mut self, ctx: &ModuleContext) -> ProbeResult {
79 let provider = ctx
81 .services
82 .get_or_create::<reovim_driver_session::bridges::BridgeProvider>();
83 provider.register(jump::bridge::JumpBridge);
84 provider.register(fold::bridge::FoldBridge);
85
86 let command_store = ctx
88 .services
89 .get_or_create::<reovim_driver_command::CommandHandlerStore>();
90 for handler in jump::command::all_commands() {
91 command_store.add(handler);
92 }
93
94 for handler in fold::command::all_commands() {
96 command_store.add(handler);
97 }
98
99 let modes = ctx.services.get_or_create::<ModeInfoStore>();
102 let parent_mode = resolve_parent_mode(ctx, &modes);
103
104 if parent_mode.is_some() {
105 command_store.add(Box::new(find_char::EnhancedFindCharCommand));
107 }
108
109 let resolvers = ctx.services.get_or_create::<ResolverRegistry>();
111 resolvers.register(jump::resolver::JumpResolver::with_parent(
112 parent_mode.clone().unwrap_or(jump::ids::JUMP_INPUT_MODE),
113 ));
114
115 modes.add(ModeInfo {
117 id: jump::ids::JUMP_INPUT_MODE,
118 display_name: "JUMP",
119 cursor_style: CursorStyle::Block,
120 accepts_char_input: true,
121 has_selection: false,
122 inherits_from: parent_mode,
123 is_entry: false,
124 });
125
126 let keybinding_store = ctx.services.get_or_create::<KeybindingStore>();
128 keybinding_store.add_all(self.keybindings());
129
130 ProbeResult::Success
131 }
132
133 #[cfg_attr(coverage_nightly, coverage(off))]
134 fn exit(&mut self) -> Result<(), ModuleError> {
135 Ok(())
136 }
137
138 fn extension_kinds(&self) -> &[&'static str] {
139 &[KIND_JUMP, KIND_FOLD]
140 }
141
142 #[cfg_attr(coverage_nightly, coverage(off))]
143 fn keybindings(&self) -> Vec<KeybindingRegistration> {
144 keybinding::all()
145 }
146}
147
148#[cfg_attr(coverage_nightly, coverage(off))]
152fn resolve_parent_mode(
153 ctx: &ModuleContext,
154 modes: &ModeInfoStore,
155) -> Option<reovim_kernel::api::v1::ModeId> {
156 let bridge_store = ctx.services.get::<ModeBridgeStore>()?;
157 let parent_str = bridge_store.find_parent("range-finder:jump-input")?;
158 let (module, name) = parent_str.split_once(':')?;
159
160 if let Some(mode_id) = modes.find_by_name(module, name) {
161 return Some(mode_id);
162 }
163 tracing::warn!("Mode bridge parent '{parent_str}' not found in ModeInfoStore");
164 None
165}
166
167#[cfg(feature = "dynamic")]
168reovim_module_macros::declare_module!(RangeFinderModule);
169
170#[cfg(test)]
171#[path = "lib_tests.rs"]
172mod tests;