on master help sign in
Add filter ability to picker
002f1adIvan Tham
book/src/keymap.md+14
@@ -169,3 +169,17 @@ This layer is a kludge of mappings I had under leader key in neovim.
169| s | Open symbol picker (current document)|
169| s | Open symbol picker (current document)|
170| w | Enter window mode |
170| w | Enter window mode |
171| space | Keep primary selection TODO: it's here because space mode replaced it |
171| space | Keep primary selection TODO: it's here because space mode replaced it |
172+
173+# Picker
174+
175+Keys to use within picker.
176+
177+| Key | Description |
178+|-----|-------------|
179+| up, ctrl-p | Previous entry |
180+| down, ctrl-n | Next entry |
181+| ctrl-space | Filter options |
182+| enter | Open selected |
183+| ctrl-h | Open horizontally |
184+| ctrl-v | Open vertically |
185+| escape, ctrl-c | Close picker |
helix-term/src/ui/picker.rs+22
@@ -23,6 +23,8 @@ pub struct Picker<T> {
23 matcher: Box<Matcher>,
23 matcher: Box<Matcher>,
24 /// (index, score)
24 /// (index, score)
25 matches: Vec<(usize, i64)>,
25 matches: Vec<(usize, i64)>,
26+ /// Filter over original options.
27+ filters: Vec<usize>, // could be optimized into bit but not worth it now
26
28
27 cursor: usize,
29 cursor: usize,
28 // pattern: String,
30 // pattern: String,
@@ -50,6 +52,7 @@ impl<T> Picker<T> {
50 options,
52 options,
51 matcher: Box::new(Matcher::default()),
53 matcher: Box::new(Matcher::default()),
52 matches: Vec::new(),
54 matches: Vec::new(),
55+ filters: Vec::new(),
53 cursor: 0,
56 cursor: 0,
54 prompt,
57 prompt,
55 format_fn: Box::new(format_fn),
58 format_fn: Box::new(format_fn),
@@ -68,6 +71,7 @@ impl<T> Picker<T> {
68 ref mut options,
71 ref mut options,
69 ref mut matcher,
72 ref mut matcher,
70 ref mut matches,
73 ref mut matches,
74+ ref filters,
71 ref format_fn,
75 ref format_fn,
72 ..
76 ..
73 } = *self;
77 } = *self;
@@ -81,6 +85,10 @@ impl<T> Picker<T> {
81 .iter()
85 .iter()
82 .enumerate()
86 .enumerate()
83 .filter_map(|(index, option)| {
87 .filter_map(|(index, option)| {
88+ // filter options first before matching
89+ if !filters.is_empty() {
90+ filters.binary_search(&index).ok()?;
91+ }
84 // TODO: maybe using format_fn isn't the best idea here
92 // TODO: maybe using format_fn isn't the best idea here
85 let text = (format_fn)(option);
93 let text = (format_fn)(option);
86 // TODO: using fuzzy_indices could give us the char idx for match highlighting
94 // TODO: using fuzzy_indices could give us the char idx for match highlighting
@@ -114,6 +122,14 @@ impl<T> Picker<T> {
114 .get(self.cursor)
122 .get(self.cursor)
115 .map(|(index, _score)| &self.options[*index])
123 .map(|(index, _score)| &self.options[*index])
116 }
124 }
125+
126+ pub fn save_filter(&mut self) {
127+ self.filters.clear();
128+ self.filters
129+ .extend(self.matches.iter().map(|(index, _)| *index));
130+ self.filters.sort_unstable(); // used for binary search later
131+ self.prompt.clear();
132+ }
117}
133}
118
134
119// process:
135// process:
@@ -205,6 +221,12 @@ impl<T: 'static> Component for Picker<T> {
205 }
221 }
206 return close_fn;
222 return close_fn;
207 }
223 }
224+ KeyEvent {
225+ code: KeyCode::Char(' '),
226+ modifiers: KeyModifiers::CONTROL,
227+ } => {
228+ self.save_filter();
229+ }
208 _ => {
230 _ => {
209 if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
231 if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
210 // TODO: recalculate only if pattern changed
232 // TODO: recalculate only if pattern changed
helix-term/src/ui/prompt.rs+7
@@ -106,6 +106,13 @@ impl Prompt {
106 self.exit_selection();
106 self.exit_selection();
107 }
107 }
108
108
109+ pub fn clear(&mut self) {
110+ self.line.clear();
111+ self.cursor = 0;
112+ self.completion = (self.completion_fn)(&self.line);
113+ self.exit_selection();
114+ }
115+
109 pub fn change_completion_selection(&mut self, direction: CompletionDirection) {
116 pub fn change_completion_selection(&mut self, direction: CompletionDirection) {
110 if self.completion.is_empty() {
117 if self.completion.is_empty() {
111 return;
118 return;