-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: Merge Picker and FilePicker #5801
refactor: Merge Picker and FilePicker #5801
Conversation
Merges the code for the Picker and FilePicker into a single Picker that can show a file preview if a preview callback is provided. This change was mainly made to facilitate refactoring out a simple skeleton of a picker that does not do any filtering to be reused in a normal Picker and a DynamicPicker (see helix-editor#5714; in particular [mikes-comment] and [gokuls-comment]). The crux of the issue is that a picker maintains a list of predefined options (eg. list of files in the directory) and (re-)filters them every time the picker prompt changes, while a dynamic picker (eg. interactive global search, helix-editor#4687) recalculates the full list of options on every prompt change. Using a filtering picker to drive a dynamic picker hence does duplicate work of filtering thousands of matches for no reason. It could also cause problems like interfering with the regex pattern in the global search. I tried to directly extract a PickerBase to be reused in Picker and FilePicker and DynamicPicker, but the problem is that DynamicPicker is actually a DynamicFilePicker (i.e. it can preview file contents) which means we would need PickerBase, Picker, FilePicker, DynamicPicker and DynamicFilePicker and then another way of sharing the previewing code between a FilePicker and a DynamicFilePicker. By merging Picker and FilePicker into Picker, we only need PickerBase, Picker and DynamicPicker. [gokuls-comment]: helix-editor#5714 (comment) [mikes-comment]: helix-editor#5714 (comment)
When Picker and FilePicker are merged, not all Pickers will be able to show a preview
15b8c3e
to
792c8f9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit layout is awesome, it feels like I just watched you make this change live 😀
This refactor makes sense to me - I think I see where you're going for making filtering/sorting optional 👍
@@ -883,15 +863,15 @@ pub type DynQueryCallback<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>, | |||
file_picker: Picker<T>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be renamed to just "picker" now?
any video link? |
options: Vec<T>, | ||
editor_data: T::Data, | ||
callback_fn: impl Fn(&mut Context, &T, Action) + 'static, | ||
callback_fn: Box<dyn Fn(&mut Context, &T, Action) + 'static>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reason behind changing from static dispatch to dynamic dispatch?
impl Fn
-> Box<dyn Fn
options: Vec<T>, | ||
editor_data: T::Data, | ||
callback_fn: impl Fn(&mut Context, &T, Action) + 'static, | ||
callback_fn: Box<dyn Fn(&mut Context, &T, Action) + 'static>, | ||
preview_fn: Option<FilePreviewFn<T>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As Picker
is generic now File prefix can be renamed from FilePreviewFn
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently the preview only works for files so I think this name fits. This type also didn't exist before this change
options: Vec<T>, | ||
editor_data: T::Data, | ||
callback_fn: impl Fn(&mut Context, &T, Action) + 'static, | ||
preview_fn: impl Fn(&Editor, &T) -> Option<FileLocation> + 'static, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better Preview can be any content not only File content.
FileLocation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing what the preview can show would be out of scope for this refactor PR I think - https://github.com/helix-editor/helix/pull/5492/files#r1070336613 is looking to change that anyways
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just calling it PreviewFn
now would be easy enough so we don't have to rename in the future?
I don't think the capability itself should be added in this PR but it would be a small change to future proof here to avoid renames (and larger diffs/merge conflicts) in the future
@@ -2616,7 +2616,7 @@ pub fn command_palette(cx: &mut Context) { | |||
} | |||
})); | |||
|
|||
let picker = Picker::new(commands, keymap, move |cx, command, _action| { | |||
let picker = Picker::without_preview(commands, keymap, move |cx, command, _action| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still name this new() we could also make the with_preview() a builder function that takes `self‘ so you'd chain these: new(..).with_preview(..)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think beside this, everything else looks okay.
Merges the code for the Picker and FilePicker into a single Picker that can show a file preview if a preview callback is provided. This change was mainly made to facilitate refactoring out a simple skeleton of a picker that does not do any filtering to be reused in a normal Picker and a DynamicPicker (see #5714; in particular @the-mikedavis's comment and @sudormrfbin's comment).
The crux of the issue is that a picker maintains a list of predefined options (eg. list of files in the directory) and (re-)filters them every time the picker prompt changes, while a dynamic picker (eg. interactive global search, #4687) recalculates the full list of options on every prompt change. Using a filtering picker to drive a dynamic picker hence does duplicate work of filtering thousands of matches for no reason. It could also cause problems like interfering with the regex pattern in the global search.
I tried to directly extract a PickerBase to be reused in Picker, FilePicker and DynamicPicker, but the problem is that DynamicPicker is actually a DynamicFilePicker (i.e. it can preview file contents) which means we would need PickerBase, Picker, FilePicker, DynamicPicker and DynamicFilePicker and then another way of sharing the previewing code between a FilePicker and a DynamicFilePicker. By merging Picker and FilePicker into Picker, we only need PickerBase, Picker and DynamicPicker.
The PR has been organized into commits that can be easily reviewed. Each commit moves a set of related functionality from Picker into FilePicker and keeps a placeholder
unimplemented!()
call in the original region. When all methods have been moved into FilePicker, the original Picker struct and impl are deleted and FilePicker is renamed to Picker. There's close to no new code, save for some new methods likePicker::with_preview
andPicker::without_preview
.