Add DynamicPicker for updating options on every key
This commit is contained in:
parent
c64debc741
commit
914d294499
3 changed files with 78 additions and 2 deletions
|
@ -19,7 +19,7 @@ pub use completion::Completion;
|
|||
pub use editor::EditorView;
|
||||
pub use markdown::Markdown;
|
||||
pub use menu::Menu;
|
||||
pub use picker::{FileLocation, FilePicker, Picker};
|
||||
pub use picker::{DynamicPicker, FileLocation, FilePicker, Picker};
|
||||
pub use popup::Popup;
|
||||
pub use prompt::{Prompt, PromptEvent};
|
||||
pub use spinner::{ProgressSpinners, Spinner};
|
||||
|
|
|
@ -69,4 +69,8 @@ impl<T: Component + 'static> Component for Overlay<T> {
|
|||
let dimensions = (self.calc_child_size)(area);
|
||||
self.content.cursor(dimensions, ctx)
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<&'static str> {
|
||||
self.content.id()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
|||
ctrl, key, shift,
|
||||
ui::{self, fuzzy_match::FuzzyQuery, EditorView},
|
||||
};
|
||||
use futures_util::future::BoxFuture;
|
||||
use tui::{
|
||||
buffer::Buffer as Surface,
|
||||
widgets::{Block, BorderType, Borders},
|
||||
|
@ -22,7 +23,7 @@ use helix_view::{
|
|||
Document, DocumentId, Editor,
|
||||
};
|
||||
|
||||
use super::menu::Item;
|
||||
use super::{menu::Item, overlay::Overlay};
|
||||
|
||||
pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72;
|
||||
/// Biggest file size to preview in bytes
|
||||
|
@ -751,3 +752,74 @@ impl<T: Item + 'static> Component for Picker<T> {
|
|||
self.prompt.cursor(area, editor)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a new list of options to replace the contents of the picker
|
||||
/// when called with the current picker query,
|
||||
pub type DynQueryCallback<T> =
|
||||
Box<dyn Fn(String, &mut Editor) -> BoxFuture<'static, anyhow::Result<Vec<T>>>>;
|
||||
|
||||
/// 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> {
|
||||
file_picker: FilePicker<T>,
|
||||
query_callback: DynQueryCallback<T>,
|
||||
}
|
||||
|
||||
impl<T: ui::menu::Item + Send> DynamicPicker<T> {
|
||||
pub const ID: &'static str = "dynamic-picker";
|
||||
|
||||
pub fn new(file_picker: FilePicker<T>, query_callback: DynQueryCallback<T>) -> Self {
|
||||
Self {
|
||||
file_picker,
|
||||
query_callback,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Item + Send + 'static> Component for DynamicPicker<T> {
|
||||
fn render(&mut self, area: Rect, surface: &mut Surface, cx: &mut Context) {
|
||||
self.file_picker.render(area, surface, cx);
|
||||
}
|
||||
|
||||
fn handle_event(&mut self, event: &Event, cx: &mut Context) -> EventResult {
|
||||
let prev_query = self.file_picker.picker.prompt.line().to_owned();
|
||||
let event_result = self.file_picker.handle_event(event, cx);
|
||||
let current_query = self.file_picker.picker.prompt.line();
|
||||
|
||||
if *current_query == prev_query || matches!(event_result, EventResult::Ignored(_)) {
|
||||
return event_result;
|
||||
}
|
||||
|
||||
let new_options = (self.query_callback)(current_query.to_owned(), cx.editor);
|
||||
|
||||
cx.jobs.callback(async move {
|
||||
let new_options = new_options.await?;
|
||||
let callback =
|
||||
crate::job::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.picker,
|
||||
None => return,
|
||||
};
|
||||
picker.options = new_options;
|
||||
picker.cursor = 0;
|
||||
picker.force_score();
|
||||
}));
|
||||
anyhow::Ok(callback)
|
||||
});
|
||||
EventResult::Consumed(None)
|
||||
}
|
||||
|
||||
fn cursor(&self, area: Rect, ctx: &Editor) -> (Option<Position>, CursorKind) {
|
||||
self.file_picker.cursor(area, ctx)
|
||||
}
|
||||
|
||||
fn required_size(&mut self, viewport: (u16, u16)) -> Option<(u16, u16)> {
|
||||
self.file_picker.required_size(viewport)
|
||||
}
|
||||
|
||||
fn id(&self) -> Option<&'static str> {
|
||||
Some(Self::ID)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue