Add filter ability to picker
Inspired by doom emacs. Able to filter picker options multiple times.
This commit is contained in:
parent
7c2fb92c91
commit
002f1ad397
3 changed files with 43 additions and 0 deletions
|
@ -169,3 +169,17 @@ This layer is a kludge of mappings I had under leader key in neovim.
|
|||
| s | Open symbol picker (current document)|
|
||||
| w | Enter window mode |
|
||||
| space | Keep primary selection TODO: it's here because space mode replaced it |
|
||||
|
||||
# Picker
|
||||
|
||||
Keys to use within picker.
|
||||
|
||||
| Key | Description |
|
||||
|-----|-------------|
|
||||
| up, ctrl-p | Previous entry |
|
||||
| down, ctrl-n | Next entry |
|
||||
| ctrl-space | Filter options |
|
||||
| enter | Open selected |
|
||||
| ctrl-h | Open horizontally |
|
||||
| ctrl-v | Open vertically |
|
||||
| escape, ctrl-c | Close picker |
|
||||
|
|
|
@ -23,6 +23,8 @@ pub struct Picker<T> {
|
|||
matcher: Box<Matcher>,
|
||||
/// (index, score)
|
||||
matches: Vec<(usize, i64)>,
|
||||
/// Filter over original options.
|
||||
filters: Vec<usize>, // could be optimized into bit but not worth it now
|
||||
|
||||
cursor: usize,
|
||||
// pattern: String,
|
||||
|
@ -50,6 +52,7 @@ impl<T> Picker<T> {
|
|||
options,
|
||||
matcher: Box::new(Matcher::default()),
|
||||
matches: Vec::new(),
|
||||
filters: Vec::new(),
|
||||
cursor: 0,
|
||||
prompt,
|
||||
format_fn: Box::new(format_fn),
|
||||
|
@ -68,6 +71,7 @@ impl<T> Picker<T> {
|
|||
ref mut options,
|
||||
ref mut matcher,
|
||||
ref mut matches,
|
||||
ref filters,
|
||||
ref format_fn,
|
||||
..
|
||||
} = *self;
|
||||
|
@ -81,6 +85,10 @@ impl<T> Picker<T> {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, option)| {
|
||||
// filter options first before matching
|
||||
if !filters.is_empty() {
|
||||
filters.binary_search(&index).ok()?;
|
||||
}
|
||||
// TODO: maybe using format_fn isn't the best idea here
|
||||
let text = (format_fn)(option);
|
||||
// TODO: using fuzzy_indices could give us the char idx for match highlighting
|
||||
|
@ -114,6 +122,14 @@ impl<T> Picker<T> {
|
|||
.get(self.cursor)
|
||||
.map(|(index, _score)| &self.options[*index])
|
||||
}
|
||||
|
||||
pub fn save_filter(&mut self) {
|
||||
self.filters.clear();
|
||||
self.filters
|
||||
.extend(self.matches.iter().map(|(index, _)| *index));
|
||||
self.filters.sort_unstable(); // used for binary search later
|
||||
self.prompt.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// process:
|
||||
|
@ -205,6 +221,12 @@ impl<T: 'static> Component for Picker<T> {
|
|||
}
|
||||
return close_fn;
|
||||
}
|
||||
KeyEvent {
|
||||
code: KeyCode::Char(' '),
|
||||
modifiers: KeyModifiers::CONTROL,
|
||||
} => {
|
||||
self.save_filter();
|
||||
}
|
||||
_ => {
|
||||
if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
|
||||
// TODO: recalculate only if pattern changed
|
||||
|
|
|
@ -106,6 +106,13 @@ impl Prompt {
|
|||
self.exit_selection();
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.line.clear();
|
||||
self.cursor = 0;
|
||||
self.completion = (self.completion_fn)(&self.line);
|
||||
self.exit_selection();
|
||||
}
|
||||
|
||||
pub fn change_completion_selection(&mut self, direction: CompletionDirection) {
|
||||
if self.completion.is_empty() {
|
||||
return;
|
||||
|
|
Loading…
Reference in a new issue