diff options
Diffstat (limited to 'helix-term/src/ui/menu.rs')
-rw-r--r-- | helix-term/src/ui/menu.rs | 51 |
1 files changed, 24 insertions, 27 deletions
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs index c73e7bed..8eeb41ee 100644 --- a/helix-term/src/ui/menu.rs +++ b/helix-term/src/ui/menu.rs @@ -1,22 +1,22 @@ -use std::{borrow::Cow, path::PathBuf}; +use std::{borrow::Cow, cmp::Reverse, path::PathBuf}; use crate::{ compositor::{Callback, Component, Compositor, Context, Event, EventResult}, ctrl, key, shift, }; +use helix_core::fuzzy::MATCHER; +use nucleo::pattern::{AtomKind, CaseMatching, Pattern}; +use nucleo::{Config, Utf32Str}; use tui::{buffer::Buffer as Surface, widgets::Table}; pub use tui::widgets::{Cell, Row}; -use fuzzy_matcher::skim::SkimMatcherV2 as Matcher; -use fuzzy_matcher::FuzzyMatcher; - use helix_view::{editor::SmartTabConfig, graphics::Rect, Editor}; use tui::layout::Constraint; -pub trait Item { +pub trait Item: Sync + Send + 'static { /// Additional editor state that is used for label calculation. - type Data; + type Data: Sync + Send + 'static; fn format(&self, data: &Self::Data) -> Row; @@ -51,9 +51,8 @@ pub struct Menu<T: Item> { cursor: Option<usize>, - matcher: Box<Matcher>, /// (index, score) - matches: Vec<(usize, i64)>, + matches: Vec<(u32, u32)>, widths: Vec<Constraint>, @@ -75,11 +74,10 @@ impl<T: Item> Menu<T> { editor_data: <T as Item>::Data, callback_fn: impl Fn(&mut Editor, Option<&T>, MenuEvent) + 'static, ) -> Self { - let matches = (0..options.len()).map(|i| (i, 0)).collect(); + let matches = (0..options.len() as u32).map(|i| (i, 0)).collect(); Self { options, editor_data, - matcher: Box::new(Matcher::default().ignore_case()), matches, cursor: None, widths: Vec::new(), @@ -94,20 +92,19 @@ impl<T: Item> Menu<T> { pub fn score(&mut self, pattern: &str) { // reuse the matches allocation self.matches.clear(); - self.matches.extend( - self.options - .iter() - .enumerate() - .filter_map(|(index, option)| { - let text = option.filter_text(&self.editor_data); - // TODO: using fuzzy_indices could give us the char idx for match highlighting - self.matcher - .fuzzy_match(&text, pattern) - .map(|score| (index, score)) - }), - ); - // Order of equal elements needs to be preserved as LSP preselected items come in order of high to low priority - self.matches.sort_by_key(|(_, score)| -score); + let mut matcher = MATCHER.lock(); + matcher.config = Config::DEFAULT; + let pattern = Pattern::new(pattern, CaseMatching::Ignore, AtomKind::Fuzzy); + let mut buf = Vec::new(); + let matches = self.options.iter().enumerate().filter_map(|(i, option)| { + let text = option.filter_text(&self.editor_data); + pattern + .score(Utf32Str::new(&text, &mut buf), &mut matcher) + .map(|score| (i as u32, score)) + }); + self.matches.extend(matches); + self.matches + .sort_unstable_by_key(|&(i, score)| (Reverse(score), i)); // reset cursor position self.cursor = None; @@ -201,7 +198,7 @@ impl<T: Item> Menu<T> { self.cursor.and_then(|cursor| { self.matches .get(cursor) - .map(|(index, _score)| &self.options[*index]) + .map(|(index, _score)| &self.options[*index as usize]) }) } @@ -209,7 +206,7 @@ impl<T: Item> Menu<T> { self.cursor.and_then(|cursor| { self.matches .get(cursor) - .map(|(index, _score)| &mut self.options[*index]) + .map(|(index, _score)| &mut self.options[*index as usize]) }) } @@ -332,7 +329,7 @@ impl<T: Item + 'static> Component for Menu<T> { .iter() .map(|(index, _score)| { // (index, self.options.get(*index).unwrap()) // get_unchecked - &self.options[*index] // get_unchecked + &self.options[*index as usize] // get_unchecked }) .collect(); |