From 5ca3ed3ef841fdf15a35fa46bcf9c1c76194492e Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sun, 25 Jun 2023 14:32:22 -0500 Subject: [PATCH] Expose IDs to be used for parsing component names This is just the picker for now but could be expanded to other components. --- helix-term/src/commands.rs | 3 ++- helix-term/src/keymap.rs | 28 ++++++++++++++++++++++++++++ helix-term/src/ui/mod.rs | 4 ++-- 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 f77e27a25..f829e4d52 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 55c107f3a..aae789339 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(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if let Ok(mode) = s.parse::() { + 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>>, /// 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 155f24356..150c2975f 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 13746cfc8..192a03a65 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 { options: Vec, editor_data: T::Data, @@ -141,6 +143,9 @@ pub struct Picker { read_buffer: Vec, /// Given an item in the picker, return the file path and line number to display. file_fn: Option>, + + /// A unique identifier for the picker as a Component + id: &'static str, } impl Picker { @@ -172,6 +177,7 @@ impl Picker { 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 Picker { self } + pub fn with_id(mut self, id: &'static str) -> Self { + self.id = id; + self + } + pub fn set_options(&mut self, new_options: Vec) { self.options = new_options; self.cursor = 0; @@ -871,6 +882,10 @@ impl Component for Picker { 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 = Box; pub type DynQueryCallback = Box BoxFuture<'static, anyhow::Result>>>; +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 { @@ -914,8 +931,6 @@ pub struct DynamicPicker { } impl DynamicPicker { - pub const ID: &'static str = "dynamic-picker"; - pub fn new(file_picker: Picker, query_callback: DynQueryCallback) -> Self { Self { file_picker, @@ -947,10 +962,11 @@ impl Component for DynamicPicker { 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::>>(Self::ID) { - Some(overlay) => &mut overlay.content.file_picker, - None => return, - }; + let picker = + match compositor.find_id::>>(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 Component for DynamicPicker { } fn id(&self) -> Option<&'static str> { - Some(Self::ID) + Some(DYNAMIC_PICKER_ID) } }