Skip to main content

reovim_picker_options/
lib.rs

1#![cfg_attr(coverage_nightly, allow(unused_features))]
2#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
3//! Option picker module for reovim.
4//!
5//! Provides a picker to browse and inspect editor options.
6//! Registers `OptionsPicker` in the `PickerRegistry` during module init.
7//! The preview panel shows detailed option metadata (type, value,
8//! default, constraint, scope, owner).
9
10use std::sync::Arc;
11
12use {
13    reovim_driver_picker::{
14        Picker, PickerAction, PickerContext, PickerData, PickerItem, PickerRegistry, PreviewContent,
15    },
16    reovim_kernel::api::v1::{Module, ModuleContext, ModuleError, ModuleId, ProbeResult, Version},
17};
18
19// ============================================================================
20// OptionsPicker
21// ============================================================================
22
23/// Picker that lists registered editor options.
24///
25/// Reads `ctx.options` and produces items for each option.
26/// The preview panel shows full metadata: type, value, default,
27/// constraint, scope, and owner module.
28pub struct OptionsPicker;
29
30impl OptionsPicker {
31    /// Create a new instance.
32    #[must_use]
33    pub const fn new() -> Self {
34        Self
35    }
36}
37
38impl Default for OptionsPicker {
39    fn default() -> Self {
40        Self::new()
41    }
42}
43
44impl Picker for OptionsPicker {
45    fn name(&self) -> &'static str {
46        "options"
47    }
48
49    fn title(&self) -> &'static str {
50        "Options"
51    }
52
53    fn items(
54        &self,
55        ctx: &PickerContext,
56        _services: &reovim_kernel::api::v1::ServiceRegistry,
57    ) -> Vec<PickerItem> {
58        ctx.options
59            .iter()
60            .map(|opt| {
61                let display = opt
62                    .owner
63                    .as_ref()
64                    .map_or_else(|| opt.name.clone(), |owner| format!("[{owner}] {}", opt.name));
65                let detail = format!("{} = {}", opt.type_name, opt.current_value);
66                // Encode full metadata into PickerData::Text for preview().
67                let data = build_preview_data(opt);
68                PickerItem {
69                    display,
70                    detail: Some(detail),
71                    data: PickerData::Text(data),
72                    icon: None,
73                }
74            })
75            .collect()
76    }
77
78    fn on_select(&self, _item: &PickerItem) -> PickerAction {
79        PickerAction::Close
80    }
81
82    #[cfg_attr(coverage_nightly, coverage(off))]
83    fn preview(
84        &self,
85        item: &PickerItem,
86        _services: &reovim_kernel::api::v1::ServiceRegistry,
87    ) -> Option<PreviewContent> {
88        let PickerData::Text(ref data) = item.data else {
89            return None;
90        };
91
92        let lines: Vec<String> = data.lines().map(String::from).collect();
93        if lines.is_empty() {
94            return None;
95        }
96
97        Some(PreviewContent {
98            lines,
99            highlight_line: Some(0),
100            file_path: None,
101            ..Default::default()
102        })
103    }
104}
105
106// ============================================================================
107// Preview data builder
108// ============================================================================
109
110/// Build a multi-line preview string from option metadata.
111///
112/// Each line is a key-value pair showing the option's full specification.
113/// This string is stored in `PickerData::Text` and split back into lines
114/// by `preview()` for display.
115fn build_preview_data(opt: &reovim_driver_picker::OptionInfo) -> String {
116    let mut lines = Vec::with_capacity(10);
117
118    lines.push(format!("  {}", opt.name));
119    if let Some(ref short) = opt.short_form {
120        lines.push(format!("  alias: {short}"));
121    }
122    lines.push(String::new());
123    lines.push(format!("  {}", opt.description));
124    lines.push(String::new());
125    lines.push(format!("  Type:     {}", opt.type_name));
126    lines.push(format!("  Value:    {}", opt.current_value));
127    lines.push(format!("  Default:  {}", opt.default_value));
128    lines.push(format!("  Scope:    {}", opt.scope));
129
130    if let Some(ref constraint) = opt.constraint {
131        lines.push(format!("  Range:    {constraint}"));
132    }
133
134    if let Some(ref owner) = opt.owner {
135        lines.push(format!("  Module:   {owner}"));
136    }
137
138    if let Some(ref choices) = opt.choices {
139        lines.push(format!("  Choices:  {}", choices.join(", ")));
140    }
141
142    lines.join("\n")
143}
144
145// ============================================================================
146// Module implementation
147// ============================================================================
148
149/// Option picker module.
150///
151/// Registers `OptionsPicker` in `PickerRegistry` during init.
152pub struct PickerOptionsModule;
153
154impl PickerOptionsModule {
155    /// Create a new instance.
156    #[must_use]
157    pub const fn new() -> Self {
158        Self
159    }
160}
161
162impl Default for PickerOptionsModule {
163    fn default() -> Self {
164        Self::new()
165    }
166}
167
168impl Module for PickerOptionsModule {
169    fn id(&self) -> ModuleId {
170        ModuleId::new("picker-options")
171    }
172
173    fn name(&self) -> &'static str {
174        "Option Picker"
175    }
176
177    fn version(&self) -> Version {
178        Version::new(0, 1, 0)
179    }
180
181    fn init(&mut self, ctx: &ModuleContext) -> ProbeResult {
182        let registry = ctx.services.get_or_create::<PickerRegistry>();
183        registry.register(Arc::new(OptionsPicker));
184        ProbeResult::Success
185    }
186
187    fn exit(&mut self) -> Result<(), ModuleError> {
188        Ok(())
189    }
190}
191
192#[cfg(feature = "dynamic")]
193reovim_module_macros::declare_module!(PickerOptionsModule);
194
195#[cfg(test)]
196#[path = "lib_tests.rs"]
197mod tests;