@@ -21,6 +21,8 @@ pub struct Picker {
21 files: Vec<PathBuf>,
21 files: Vec<PathBuf>,
22 // filter: String,
22 // filter: String,
23 matcher: Box<Matcher>,
23 matcher: Box<Matcher>,
25+ matches: Vec<(usize, i64)>,
25 cursor: usize,
27 cursor: usize,
26 // pattern: String,
28 // pattern: String,
@@ -51,20 +53,46 @@ impl Picker {
52 const MAX: usize = 1024;
54 const MAX: usize = 1024;
54− Self {
56+ let mut picker = Self {
55 files: files.take(MAX).collect(),
57 files: files.take(MAX).collect(),
56 matcher: Box::new(Matcher::default()),
58 matcher: Box::new(Matcher::default()),
57 cursor: 0,
60 cursor: 0,
64+ // TODO: scoring on empty input should just use a fastpath
62− pub fn score(&mut self, pattern: &str) {
70+ pub fn score(&mut self) {
71+ // need to borrow via pattern match otherwise it complains about simultaneous borrow
79+ let pattern = &self.prompt.line;
81+ // reuse the matches allocation
63− self.files.iter().filter_map(|path| match path.to_str() {
83+ matches.extend(self.files.iter().enumerate().filter_map(|(index, path)| {
84+ match path.to_str() {
64− // TODO: using fuzzy_indices could give us the char idx for match highlighting
85+ // TODO: using fuzzy_indices could give us the char idx for match highlighting
86+ Some(path) => matcher
65− Some(path) => (self.matcher.fuzzy_match(path, pattern)),
87+ .fuzzy_match(path, pattern)
88+ .map(|score| (index, score)),
66− None => None,
89+ None => None,
92+ matches.sort_unstable_by_key(|(_, score)| -score);
94+ // reset cursor position
70 pub fn move_up(&mut self) {
98 pub fn move_up(&mut self) {
@@ -77,6 +105,12 @@ impl Picker {
77 self.cursor += 1;
105 self.cursor += 1;
109+ pub fn selection(&self) -> Option<&PathBuf> {
112+ .map(|(index, _score)| &self.files[*index])
82// process:
116// process:
@@ -125,7 +159,15 @@ impl Component for Picker {
126 return close_fn;
160 return close_fn;
128− _ => return self.prompt.handle_event(event, cx),
163+ match self.prompt.handle_event(event, cx) {
164+ EventResult::Consumed(_) => {
165+ // TODO: recalculate only if pattern changed
131 EventResult::Consumed(None)
173 EventResult::Consumed(None)
@@ -184,7 +226,12 @@ impl Component for Picker {
184 let selected = Style::default().fg(Color::Rgb(255, 255, 255));
226 let selected = Style::default().fg(Color::Rgb(255, 255, 255));
186 let rows = inner.height - 2; // -1 for search bar
228 let rows = inner.height - 2; // -1 for search bar
230+ let files = self.matches.iter().map(|(index, _score)| {
231+ (index, self.files.get(*index).unwrap()) // get_unchecked
187− for (i, file) in self.files.iter().take(rows as usize).enumerate() {
234+ for (i, (_index, file)) in files.take(rows as usize).enumerate() {
188 if i == self.cursor {
235 if i == self.cursor {
189 surface.set_string(inner.x + 1, inner.y + 2 + i as u16, ">", selected);
236 surface.set_string(inner.x + 1, inner.y + 2 + i as u16, ">", selected);