reovim_plugin_fold/
lib.rs1pub mod commands;
17pub mod stage;
18pub mod state;
19
20#[cfg(test)]
21mod tests;
22
23use std::{any::TypeId, sync::Arc};
24
25use reovim_core::{
26 event_bus::{BufferClosed, EventBus, EventResult, FoldRangesComputed},
27 plugin::{Plugin, PluginContext, PluginId, PluginStateRegistry},
28};
29
30use {stage::FoldRenderStage, state::SharedFoldManager};
31
32pub use commands::{FoldClose, FoldCloseAll, FoldOpen, FoldOpenAll, FoldRangesUpdated, FoldToggle};
34
35pub struct FoldPlugin {
44 fold_manager: Arc<SharedFoldManager>,
45}
46
47impl Default for FoldPlugin {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53impl FoldPlugin {
54 #[must_use]
56 pub fn new() -> Self {
57 Self {
58 fold_manager: Arc::new(SharedFoldManager::new()),
59 }
60 }
61}
62
63impl Plugin for FoldPlugin {
64 fn id(&self) -> PluginId {
65 PluginId::new("reovim:fold")
66 }
67
68 fn name(&self) -> &'static str {
69 "Fold"
70 }
71
72 fn description(&self) -> &'static str {
73 "Code folding with treesitter integration"
74 }
75
76 fn dependencies(&self) -> Vec<TypeId> {
77 vec![]
79 }
80
81 fn build(&self, ctx: &mut PluginContext) {
82 let _ = ctx.register_command(FoldToggle::default_instance());
84 let _ = ctx.register_command(FoldOpen::default_instance());
85 let _ = ctx.register_command(FoldClose::default_instance());
86 let _ = ctx.register_command(FoldOpenAll::default_instance());
87 let _ = ctx.register_command(FoldCloseAll::default_instance());
88
89 let stage = Arc::new(FoldRenderStage::new(Arc::clone(&self.fold_manager)));
91 ctx.register_render_stage(stage);
92
93 tracing::debug!("FoldPlugin: registered commands and render stage");
94 }
95
96 fn init_state(&self, registry: &PluginStateRegistry) {
97 registry.register(Arc::clone(&self.fold_manager));
99 registry.set_visibility_source(Arc::clone(&self.fold_manager)
100 as Arc<dyn reovim_core::visibility::BufferVisibilitySource>);
101
102 tracing::debug!("FoldPlugin: initialized SharedFoldManager");
103 }
104
105 fn subscribe(&self, bus: &EventBus, state: Arc<PluginStateRegistry>) {
106 let state_clone = Arc::clone(&state);
108 bus.subscribe::<FoldToggle, _>(100, move |event, _ctx| {
109 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
110 fm.with_mut(|m| m.toggle(event.buffer_id, event.line));
111 });
112 tracing::trace!(
113 buffer_id = event.buffer_id,
114 line = event.line,
115 "FoldPlugin: toggled fold"
116 );
117 EventResult::Handled
118 });
119
120 let state_clone = Arc::clone(&state);
122 bus.subscribe::<FoldOpen, _>(100, move |event, _ctx| {
123 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
124 fm.with_mut(|m| m.open(event.buffer_id, event.line));
125 });
126 tracing::trace!(
127 buffer_id = event.buffer_id,
128 line = event.line,
129 "FoldPlugin: opened fold"
130 );
131 EventResult::Handled
132 });
133
134 let state_clone = Arc::clone(&state);
136 bus.subscribe::<FoldClose, _>(100, move |event, _ctx| {
137 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
138 fm.with_mut(|m| m.close(event.buffer_id, event.line));
139 });
140 tracing::trace!(
141 buffer_id = event.buffer_id,
142 line = event.line,
143 "FoldPlugin: closed fold"
144 );
145 EventResult::Handled
146 });
147
148 let state_clone = Arc::clone(&state);
150 bus.subscribe::<FoldOpenAll, _>(100, move |event, _ctx| {
151 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
152 fm.with_mut(|m| m.open_all(event.buffer_id));
153 });
154 tracing::trace!(buffer_id = event.buffer_id, "FoldPlugin: opened all folds");
155 EventResult::Handled
156 });
157
158 let state_clone = Arc::clone(&state);
160 bus.subscribe::<FoldCloseAll, _>(100, move |event, _ctx| {
161 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
162 fm.with_mut(|m| m.close_all(event.buffer_id));
163 });
164 tracing::trace!(buffer_id = event.buffer_id, "FoldPlugin: closed all folds");
165 EventResult::Handled
166 });
167
168 let state_clone = Arc::clone(&state);
170 bus.subscribe::<FoldRangesUpdated, _>(50, move |event, _ctx| {
171 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
172 fm.with_mut(|m| m.set_ranges(event.buffer_id, event.ranges.clone()));
173 });
174 tracing::trace!(
175 buffer_id = event.buffer_id,
176 count = event.ranges.len(),
177 "FoldPlugin: updated fold ranges (plugin event)"
178 );
179 EventResult::Handled
180 });
181
182 let state_clone = Arc::clone(&state);
184 bus.subscribe::<FoldRangesComputed, _>(50, move |event, _ctx| {
185 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
186 fm.with_mut(|m| m.set_ranges(event.buffer_id, event.ranges.clone()));
187 });
188 tracing::trace!(
189 buffer_id = event.buffer_id,
190 count = event.ranges.len(),
191 "FoldPlugin: updated fold ranges (treesitter)"
192 );
193 EventResult::Handled
194 });
195
196 let state_clone = Arc::clone(&state);
198 bus.subscribe::<BufferClosed, _>(100, move |event, _ctx| {
199 state_clone.with::<Arc<SharedFoldManager>, _, _>(|fm| {
200 fm.with_mut(|m| m.remove_buffer(event.buffer_id));
201 });
202 tracing::trace!(
203 buffer_id = event.buffer_id,
204 "FoldPlugin: cleaned up fold state for closed buffer"
205 );
206 EventResult::Handled
207 });
208
209 tracing::debug!("FoldPlugin: subscribed to fold events");
210 }
211}
212
213pub use {
217 reovim_core::folding::{FoldKind, FoldRange},
218 state::{FoldManager, FoldState},
219};
220