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:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user