Provide search functionality through the TUI #134
@ -108,6 +108,7 @@ pub trait IAppInteractReload {
|
|||||||
|
|
||||||
pub trait IAppInteractSearch {
|
pub trait IAppInteractSearch {
|
||||||
fn append_character(&mut self, ch: char);
|
fn append_character(&mut self, ch: char);
|
||||||
|
fn search_next(&mut self);
|
||||||
fn remove_character(&mut self);
|
fn remove_character(&mut self);
|
||||||
fn finish_search(&mut self);
|
fn finish_search(&mut self);
|
||||||
}
|
}
|
||||||
@ -246,6 +247,7 @@ impl<MH: IMusicHoard> IAppInteractBrowse for App<MH> {
|
|||||||
fn begin_search(&mut self) {
|
fn begin_search(&mut self) {
|
||||||
assert!(self.state.is_browse());
|
assert!(self.state.is_browse());
|
||||||
self.state = AppState::Search(String::new());
|
self.state = AppState::Search(String::new());
|
||||||
|
// FIXME: this should be the entire selection - not just the artist.
|
||||||
self.memo = vec![self.selection.selected_artist()];
|
self.memo = vec![self.selection.selected_artist()];
|
||||||
self.selection
|
self.selection
|
||||||
.reset_artist(self.music_hoard.get_collection());
|
.reset_artist(self.music_hoard.get_collection());
|
||||||
@ -296,7 +298,6 @@ impl<MH: IMusicHoard> IAppInteractReloadPrivate for App<MH> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: add `search_next` to find next match
|
|
||||||
// FIXME: once `search_next` is added, backspace should step back. If the previous action was
|
// FIXME: once `search_next` is added, backspace should step back. If the previous action was
|
||||||
// `search_next` then no character should be removed. If the previous action was to append
|
// `search_next` then no character should be removed. If the previous action was to append
|
||||||
// a character, a character should be removed. When in doubt see how Emacs's isearch works.
|
// a character, a character should be removed. When in doubt see how Emacs's isearch works.
|
||||||
@ -306,7 +307,14 @@ impl<MH: IMusicHoard> IAppInteractSearch for App<MH> {
|
|||||||
let collection = self.music_hoard.get_collection();
|
let collection = self.music_hoard.get_collection();
|
||||||
let search = self.state.as_mut().unwrap_search();
|
let search = self.state.as_mut().unwrap_search();
|
||||||
search.push(ch);
|
search.push(ch);
|
||||||
let prev = self.selection.incremental_artist_search(collection, search);
|
let prev = self.selection.incremental_artist_search(collection, search, false);
|
||||||
|
self.memo.push(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_next(&mut self) {
|
||||||
|
let collection = self.music_hoard.get_collection();
|
||||||
|
let search = self.state.as_mut().unwrap_search();
|
||||||
|
let prev = self.selection.incremental_artist_search(collection, search, true);
|
||||||
self.memo.push(prev);
|
self.memo.push(prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,8 +108,9 @@ impl Selection {
|
|||||||
&mut self,
|
&mut self,
|
||||||
collection: &Collection,
|
collection: &Collection,
|
||||||
artist_name: &str,
|
artist_name: &str,
|
||||||
|
next: bool,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
self.artist.incremental_search(collection, artist_name)
|
self.artist.incremental_search(collection, artist_name, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_selection(&mut self, collection: &Collection, delta: Delta) {
|
pub fn increment_selection(&mut self, collection: &Collection, delta: Delta) {
|
||||||
@ -265,14 +266,22 @@ impl ArtistSelection {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn incremental_search(&mut self, artists: &[Artist], artist_name: &str) -> Option<usize> {
|
fn incremental_search(
|
||||||
|
&mut self,
|
||||||
|
artists: &[Artist],
|
||||||
|
artist_name: &str,
|
||||||
|
next: bool,
|
||||||
|
) -> Option<usize> {
|
||||||
let previous = self.state.list.selected();
|
let previous = self.state.list.selected();
|
||||||
|
|
||||||
if let Some(index) = self.state.list.selected() {
|
if let Some(mut index) = self.state.list.selected() {
|
||||||
let case_sensitive = Self::is_case_sensitive(artist_name);
|
let case_sensitive = Self::is_case_sensitive(artist_name);
|
||||||
let char_sensitive = Self::is_char_sensitive(artist_name);
|
let char_sensitive = Self::is_char_sensitive(artist_name);
|
||||||
let search = Self::normalize_search(artist_name, !case_sensitive, !char_sensitive);
|
let search = Self::normalize_search(artist_name, !case_sensitive, !char_sensitive);
|
||||||
|
|
||||||
|
if next && ((index + 1) < artists.len()) {
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
let slice = &artists[index..];
|
let slice = &artists[index..];
|
||||||
|
|
||||||
let result = slice.iter().position(|probe| {
|
let result = slice.iter().position(|probe| {
|
||||||
|
@ -146,6 +146,16 @@ impl<APP: IAppInteract> IEventHandlerPrivate<APP> for EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_search_key_event(app: &mut <APP as IAppInteract>::SS, key_event: KeyEvent) {
|
fn handle_search_key_event(app: &mut <APP as IAppInteract>::SS, key_event: KeyEvent) {
|
||||||
|
if key_event.modifiers == KeyModifiers::CONTROL {
|
||||||
|
match key_event.code {
|
||||||
|
KeyCode::Char('s') | KeyCode::Char('S') => {
|
||||||
|
app.search_next();
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
match key_event.code {
|
match key_event.code {
|
||||||
// Add/remove character to search.
|
// Add/remove character to search.
|
||||||
KeyCode::Char(ch) => app.append_character(ch),
|
KeyCode::Char(ch) => app.append_character(ch),
|
||||||
|
Loading…
Reference in New Issue
Block a user