aboutsummaryrefslogtreecommitdiff
path: root/helix-term/src/ui/picker.rs
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term/src/ui/picker.rs')
-rw-r--r--helix-term/src/ui/picker.rs64
1 files changed, 35 insertions, 29 deletions
diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs
index a56455d7..c7149c61 100644
--- a/helix-term/src/ui/picker.rs
+++ b/helix-term/src/ui/picker.rs
@@ -1,7 +1,7 @@
use crate::{
compositor::{Component, Compositor, Context, Event, EventResult},
ctrl, key, shift,
- ui::{self, EditorView},
+ ui::{self, fuzzy_match::FuzzyQuery, EditorView},
};
use tui::{
buffer::Buffer as Surface,
@@ -9,7 +9,6 @@ use tui::{
};
use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
-use fuzzy_matcher::FuzzyMatcher;
use tui::widgets::Widget;
use std::time::Instant;
@@ -161,6 +160,27 @@ impl<T: Item> FilePicker<T> {
self.preview_cache.insert(path.to_owned(), preview);
Preview::Cached(&self.preview_cache[path])
}
+
+ fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult {
+ // Try to find a document in the cache
+ let doc = self
+ .current_file(cx.editor)
+ .and_then(|(path, _range)| self.preview_cache.get_mut(&path))
+ .and_then(|cache| match cache {
+ CachedPreview::Document(doc) => Some(doc),
+ _ => None,
+ });
+
+ // Then attempt to highlight it if it has no language set
+ if let Some(doc) = doc {
+ if doc.language_config().is_none() {
+ let loader = cx.editor.syn_loader.clone();
+ doc.detect_language(loader);
+ }
+ }
+
+ EventResult::Consumed(None)
+ }
}
impl<T: Item + 'static> Component for FilePicker<T> {
@@ -261,6 +281,9 @@ impl<T: Item + 'static> Component for FilePicker<T> {
}
fn handle_event(&mut self, event: &Event, ctx: &mut Context) -> EventResult {
+ if let Event::IdleTimeout = event {
+ return self.handle_idle_timeout(ctx);
+ }
// TODO: keybinds for scrolling preview
self.picker.handle_event(event, ctx)
}
@@ -287,8 +310,6 @@ pub struct Picker<T: Item> {
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
/// Current height of the completions box
completion_height: u16,
@@ -323,7 +344,6 @@ impl<T: Item> Picker<T> {
editor_data,
matcher: Box::new(Matcher::default()),
matches: Vec::new(),
- filters: Vec::new(),
cursor: 0,
prompt,
previous_pattern: String::new(),
@@ -365,13 +385,14 @@ impl<T: Item> Picker<T> {
.map(|(index, _option)| (index, 0)),
);
} else if pattern.starts_with(&self.previous_pattern) {
+ let query = FuzzyQuery::new(pattern);
// optimization: if the pattern is a more specific version of the previous one
// then we can score the filtered set.
self.matches.retain_mut(|(index, score)| {
let option = &self.options[*index];
let text = option.sort_text(&self.editor_data);
- match self.matcher.fuzzy_match(&text, pattern) {
+ match query.fuzzy_match(&text, &self.matcher) {
Some(s) => {
// Update the score
*score = s;
@@ -384,23 +405,17 @@ impl<T: Item> Picker<T> {
self.matches
.sort_unstable_by_key(|(_, score)| Reverse(*score));
} else {
+ let query = FuzzyQuery::new(pattern);
self.matches.clear();
self.matches.extend(
self.options
.iter()
.enumerate()
.filter_map(|(index, option)| {
- // filter options first before matching
- if !self.filters.is_empty() {
- // TODO: this filters functionality seems inefficient,
- // instead store and operate on filters if any
- self.filters.binary_search(&index).ok()?;
- }
-
let text = option.filter_text(&self.editor_data);
- self.matcher
- .fuzzy_match(&text, pattern)
+ query
+ .fuzzy_match(&text, &self.matcher)
.map(|score| (index, score))
}),
);
@@ -460,14 +475,6 @@ impl<T: Item> Picker<T> {
.map(|(index, _score)| &self.options[*index])
}
- pub fn save_filter(&mut self, cx: &Context) {
- self.filters.clear();
- self.filters
- .extend(self.matches.iter().map(|(index, _)| *index));
- self.filters.sort_unstable(); // used for binary search later
- self.prompt.clear(cx.editor);
- }
-
pub fn toggle_preview(&mut self) {
self.show_preview = !self.show_preview;
}
@@ -505,6 +512,9 @@ impl<T: Item + 'static> Component for Picker<T> {
compositor.last_picker = compositor.pop();
})));
+ // So that idle timeout retriggers
+ cx.editor.reset_idle_timer();
+
match key_event {
shift!(Tab) | key!(Up) | ctrl!('p') => {
self.move_by(1, Direction::Backward);
@@ -545,9 +555,6 @@ impl<T: Item + 'static> Component for Picker<T> {
}
return close_fn;
}
- ctrl!(' ') => {
- self.save_filter(cx);
- }
ctrl!('t') => {
self.toggle_preview();
}
@@ -630,9 +637,8 @@ impl<T: Item + 'static> Component for Picker<T> {
}
let spans = option.label(&self.editor_data);
- let (_score, highlights) = self
- .matcher
- .fuzzy_indices(&String::from(&spans), self.prompt.line())
+ let (_score, highlights) = FuzzyQuery::new(self.prompt.line())
+ .fuzzy_indicies(&String::from(&spans), &self.matcher)
.unwrap_or_default();
spans.0.into_iter().fold(inner, |pos, span| {