Expose IDs to be used for parsing component names

This is just the picker for now but could be expanded to other
components.
This commit is contained in:
Michael Davis 2023-06-25 14:32:22 -05:00
parent 21169c77fd
commit 5ca3ed3ef8
No known key found for this signature in database
4 changed files with 55 additions and 10 deletions

View File

@ -2591,7 +2591,8 @@ fn format(&self, _data: &Self::Data) -> Row {
.primary()
.cursor_line(doc.text().slice(..));
Some((meta.id.into(), Some((line, line))))
});
})
.with_id("buffer-picker");
cx.push_layer(Box::new(overlaid(picker)));
}

View File

@ -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

View File

@ -7,7 +7,7 @@
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 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};

View File

@ -114,6 +114,8 @@ fn placeholder(&self) -> &str {
}
}
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 @@ pub fn new(
preview_cache: HashMap::new(),
read_buffer: Vec::with_capacity(1024),
file_fn: None,
id: PICKER_ID,
};
picker.calculate_column_widths();
@ -205,6 +211,11 @@ pub fn with_preview(
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 @@ fn required_size(&mut self, (width, height): (u16, u16)) -> Option<(u16, u16)> {
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 @@ fn cmp(&self, other: &Self) -> Ordering {
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,7 +962,8 @@ fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
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) {
let picker =
match compositor.find_id::<Overlay<DynamicPicker<T>>>(DYNAMIC_PICKER_ID) {
Some(overlay) => &mut overlay.content.file_picker,
None => return,
};
@ -968,6 +984,6 @@ fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
}
fn id(&self) -> Option<&'static str> {
Some(Self::ID)
Some(DYNAMIC_PICKER_ID)
}
}