Skip to content

Commit

Permalink
Refactored ui::Picker (score, add_options)
Browse files Browse the repository at this point in the history
    - ui::Picker::score() now optionally supports retaining the current selected option
    - Added method add_options to extend options (useful, if multiple options provider asynchronously add options)
  • Loading branch information
Philipp-M committed May 24, 2022
1 parent 5040679 commit a376e02
Showing 1 changed file with 57 additions and 22 deletions.
79 changes: 57 additions & 22 deletions helix-term/src/ui/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ impl<T> FilePicker<T> {
self
}

pub fn add_options(&mut self, options: Vec<T>) {
self.picker.add_options(options);
}

fn current_file(&self, editor: &Editor) -> Option<FileLocation> {
self.picker
.selection()
Expand Down Expand Up @@ -333,27 +337,35 @@ impl<T> Picker<T> {
completion_height: 0,
};

// scoring on empty input:
// TODO: just reuse score()
picker.matches.extend(
picker
.options
.iter()
.enumerate()
.map(|(index, _option)| (index, 0)),
);

picker.re_score(None, true, true);
picker
}

pub fn score(&mut self) {
let now = Instant::now();
pub fn re_score(
&mut self,
pattern: Option<String>,
reset_cursor: bool,
force_recalculation: bool,
) {
let cursor = self.cursor;
if reset_cursor {
self.cursor = 0
}

let pattern = self.prompt.line();
let pattern = match pattern {
Some(pattern) if pattern == self.previous_pattern && !force_recalculation => return,
None if !force_recalculation => return,
None => self.previous_pattern.clone(),
Some(pattern) => pattern,
};

if pattern == &self.previous_pattern {
return;
}
let now = Instant::now();

let prev_matched_option = if !reset_cursor {
self.matches.get(cursor).map(|(index, _)| *index)
} else {
None
};

if pattern.is_empty() {
// Fast path for no pattern.
Expand All @@ -377,7 +389,7 @@ impl<T> Picker<T> {
// TODO: maybe using format_fn isn't the best idea here
let text = (self.format_fn)(option);

match self.matcher.fuzzy_match(&text, pattern) {
match self.matcher.fuzzy_match(&text, &pattern) {
Some(s) => {
// Update the score
*score = s;
Expand Down Expand Up @@ -407,7 +419,7 @@ impl<T> Picker<T> {
let text = (self.format_fn)(option);

self.matcher
.fuzzy_match(&text, pattern)
.fuzzy_match(&text, &pattern)
.map(|score| (index, score))
}),
);
Expand All @@ -417,9 +429,32 @@ impl<T> Picker<T> {

log::debug!("picker score {:?}", Instant::now().duration_since(now));

// reset cursor position
self.cursor = 0;
self.previous_pattern.clone_from(pattern);
// reset cursor position or recover position based on previous matched option
if let Some(prev_matched_option) = prev_matched_option {
self.cursor = self
.matches
.iter()
.enumerate()
.find_map(|(index, m)| {
if m.0 == prev_matched_option {
Some(index)
} else {
None
}
})
.unwrap_or(0);
}
self.previous_pattern = pattern;
}

pub fn score(&mut self, reset_cursor: bool) {
let pattern = self.prompt.line().clone();
self.re_score(Some(pattern), reset_cursor, false);
}

pub fn add_options(&mut self, mut options: Vec<T>) {
self.options.append(&mut options);
self.re_score(None, false, true);
}

/// Move the cursor by a number of lines, either down (`Forward`) or up (`Backward`)
Expand Down Expand Up @@ -545,7 +580,7 @@ impl<T: 'static> Component for Picker<T> {
_ => {
if let EventResult::Consumed(_) = self.prompt.handle_event(event, cx) {
// TODO: recalculate only if pattern changed
self.score();
self.score(true);
}
}
}
Expand Down

0 comments on commit a376e02

Please sign in to comment.