Vim like search (#279)

* add quick search within a list

* vim like search navigation

* close cmd line with esc

* format

* document changes in README
This commit is contained in:
Moshe Sherman
2020-10-05 14:50:12 +03:00
committed by GitHub
parent fc79889665
commit f2b4f01242
6 changed files with 121 additions and 12 deletions

View File

@@ -1,4 +1,4 @@
use std::cmp::{max, min};
use std::cmp::{max, min, Ordering};
use std::sync::{Arc, RwLock};
use cursive::align::HAlign;
@@ -9,7 +9,7 @@ use cursive::view::ScrollBase;
use cursive::{Cursive, Printer, Rect, Vec2};
use unicode_width::UnicodeWidthStr;
use crate::command::{Command, GotoMode, MoveAmount, MoveMode, TargetMode};
use crate::command::{Command, GotoMode, JumpMode, MoveAmount, MoveMode, TargetMode};
use crate::commands::CommandResult;
use crate::library::Library;
use crate::playable::Playable;
@@ -89,6 +89,8 @@ pub struct ListView<I: ListItem> {
content: Arc<RwLock<Vec<I>>>,
last_content_len: usize,
selected: usize,
search_indexes: Vec<usize>,
search_selected_index: usize,
last_size: Vec2,
scrollbar: ScrollBase,
queue: Arc<Queue>,
@@ -102,6 +104,8 @@ impl<I: ListItem> ListView<I> {
content,
last_content_len: 0,
selected: 0,
search_indexes: Vec::new(),
search_selected_index: 0,
last_size: Vec2::new(0, 0),
scrollbar: ScrollBase::new(),
queue,
@@ -132,6 +136,20 @@ impl<I: ListItem> ListView<I> {
self.selected
}
pub fn get_indexes_of(&self, query: &String) -> Vec<usize> {
let content = self.content.read().unwrap();
content
.iter()
.enumerate()
.filter(|(_, i)| {
i.display_left()
.to_lowercase()
.contains(&query[..].to_lowercase())
})
.map(|(i, _)| i)
.collect()
}
pub fn move_focus_to(&mut self, target: usize) {
let len = self.content.read().unwrap().len().saturating_sub(1);
self.selected = min(target, len);
@@ -395,6 +413,47 @@ impl<I: ListItem + Clone> ViewExt for ListView<I> {
return Ok(CommandResult::Consumed(None));
}
Command::Jump(mode) => match mode {
JumpMode::Query(query) => {
self.search_indexes = self.get_indexes_of(query);
self.search_selected_index = 0;
match self.search_indexes.get(0) {
Some(&index) => {
self.move_focus_to(index);
return Ok(CommandResult::Consumed(None));
}
None => return Ok(CommandResult::Ignored),
}
}
JumpMode::Next => {
let len = self.search_indexes.len();
if len == 0 {
return Ok(CommandResult::Ignored);
}
let index = self.search_selected_index;
let next_index = match index.cmp(&(len - 1)) {
Ordering::Equal => 0,
_ => index + 1,
};
self.move_focus_to(self.search_indexes[next_index]);
self.search_selected_index = next_index;
return Ok(CommandResult::Consumed(None));
}
JumpMode::Previous => {
let len = self.search_indexes.len();
if len == 0 {
return Ok(CommandResult::Ignored);
}
let index = self.search_selected_index;
let prev_index = match index.cmp(&0) {
Ordering::Equal => len - 1,
_ => index - 1,
};
self.move_focus_to(self.search_indexes[prev_index]);
self.search_selected_index = prev_index;
return Ok(CommandResult::Consumed(None));
}
},
Command::Move(mode, amount) => {
let last_idx = self.content.read().unwrap().len().saturating_sub(1);