Unnamed repository; edit this file 'description' to name the repository.
Expose IDs to be used for parsing component names
This is just the picker for now but could be expanded to other
components.
| -rw-r--r-- | helix-term/src/commands.rs | 3 | ||||
| -rw-r--r-- | helix-term/src/keymap.rs | 28 | ||||
| -rw-r--r-- | helix-term/src/ui/mod.rs | 4 | ||||
| -rw-r--r-- | helix-term/src/ui/picker.rs | 30 |
4 files changed, 55 insertions, 10 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index f77e27a2..f829e4d5 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2591,7 +2591,8 @@ fn buffer_picker(cx: &mut Context) { .primary() .cursor_line(doc.text().slice(..)); Some((meta.id.into(), Some((line, line)))) - }); + }) + .with_id("buffer-picker"); cx.push_layer(Box::new(overlaid(picker))); } diff --git a/helix-term/src/keymap.rs b/helix-term/src/keymap.rs index 55c107f3..aae78933 100644 --- a/helix-term/src/keymap.rs +++ b/helix-term/src/keymap.rs @@ -279,6 +279,34 @@ pub enum Domain { Component(&'static str), } +const REMAPPABLE_COMPONENTS: [&'static str; 3] = [ + crate::ui::DYNAMIC_PICKER_ID, + crate::ui::PICKER_ID, + // TODO: make it a constant + "buffer-picker", +]; + +impl<'de> Deserialize<'de> for Domain { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if let Ok(mode) = s.parse::<Mode>() { + return Ok(Domain::Mode(mode)); + } else if let Some(name) = REMAPPABLE_COMPONENTS + .iter() + .find(|name| **name == s.as_str()) + { + Ok(Domain::Component(name)) + } else { + Err(serde::de::Error::custom(format!( + "Unknown keymap domain {s}. Expected a mode or component name" + ))) + } + } +} + pub struct Keymaps { pub map: Box<dyn DynAccess<HashMap<Domain, KeyTrie>>>, /// Stores pending keys waiting for the next key. This is relative to a diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 155f2435..150c2975 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -7,7 +7,7 @@ pub mod lsp; mod markdown; pub mod menu; pub mod overlay; -mod picker; +pub mod picker; pub mod popup; mod prompt; mod spinner; @@ -21,7 +21,7 @@ pub use completion::{Completion, CompletionItem}; pub use editor::EditorView; pub use markdown::Markdown; pub use menu::Menu; -pub use picker::{DynamicPicker, FileLocation, Picker}; +pub use picker::{DynamicPicker, FileLocation, Picker, DYNAMIC_PICKER_ID, PICKER_ID}; pub use popup::Popup; pub use prompt::{Prompt, PromptEvent}; pub use spinner::{ProgressSpinners, Spinner}; diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs index 13746cfc..192a03a6 100644 --- a/helix-term/src/ui/picker.rs +++ b/helix-term/src/ui/picker.rs @@ -114,6 +114,8 @@ impl Preview<'_, '_> { } } +pub const PICKER_ID: &'static str = "picker"; + pub struct Picker<T: Item> { options: Vec<T>, editor_data: T::Data, @@ -141,6 +143,9 @@ pub struct Picker<T: Item> { read_buffer: Vec<u8>, /// Given an item in the picker, return the file path and line number to display. file_fn: Option<FileCallback<T>>, + + /// A unique identifier for the picker as a Component + id: &'static str, } impl<T: Item + 'static> Picker<T> { @@ -172,6 +177,7 @@ impl<T: Item + 'static> Picker<T> { preview_cache: HashMap::new(), read_buffer: Vec::with_capacity(1024), file_fn: None, + id: PICKER_ID, }; picker.calculate_column_widths(); @@ -205,6 +211,11 @@ impl<T: Item + 'static> Picker<T> { self } + pub fn with_id(mut self, id: &'static str) -> Self { + self.id = id; + self + } + pub fn set_options(&mut self, new_options: Vec<T>) { self.options = new_options; self.cursor = 0; @@ -871,6 +882,10 @@ impl<T: Item + 'static> Component for Picker<T> { self.completion_height = height.saturating_sub(4); Some((width, height)) } + + fn id(&self) -> Option<&'static str> { + Some(self.id) + } } #[derive(PartialEq, Eq, Debug)] @@ -905,6 +920,8 @@ type PickerCallback<T> = Box<dyn Fn(&mut Context, &T, Action)>; pub type DynQueryCallback<T> = Box<dyn Fn(String, &mut Editor) -> BoxFuture<'static, anyhow::Result<Vec<T>>>>; +pub const DYNAMIC_PICKER_ID: &'static str = "dynamic-picker"; + /// A picker that updates its contents via a callback whenever the /// query string changes. Useful for live grep, workspace symbols, etc. pub struct DynamicPicker<T: ui::menu::Item + Send> { @@ -914,8 +931,6 @@ pub struct DynamicPicker<T: ui::menu::Item + Send> { } impl<T: ui::menu::Item + Send> DynamicPicker<T> { - pub const ID: &'static str = "dynamic-picker"; - pub fn new(file_picker: Picker<T>, query_callback: DynQueryCallback<T>) -> Self { Self { file_picker, @@ -947,10 +962,11 @@ impl<T: Item + Send + 'static> Component for DynamicPicker<T> { let callback = Callback::EditorCompositor(Box::new(move |editor, compositor| { // Wrapping of pickers in overlay is done outside the picker code, // so this is fragile and will break if wrapped in some other widget. - let picker = match compositor.find_id::<Overlay<DynamicPicker<T>>>(Self::ID) { - Some(overlay) => &mut overlay.content.file_picker, - None => return, - }; + let picker = + match compositor.find_id::<Overlay<DynamicPicker<T>>>(DYNAMIC_PICKER_ID) { + Some(overlay) => &mut overlay.content.file_picker, + None => return, + }; picker.set_options(new_options); editor.reset_idle_timer(); })); @@ -968,6 +984,6 @@ impl<T: Item + Send + 'static> Component for DynamicPicker<T> { } fn id(&self) -> Option<&'static str> { - Some(Self::ID) + Some(DYNAMIC_PICKER_ID) } } |