Implement step back

This commit is contained in:
Wojciech Kozlowski 2024-02-12 23:09:19 +01:00
parent 488d20273e
commit a29a3fa3ce
3 changed files with 30 additions and 19 deletions

View File

@ -109,7 +109,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 search_next(&mut self);
fn remove_character(&mut self); fn step_back(&mut self);
fn finish_search(&mut self); fn finish_search(&mut self);
} }
@ -142,7 +142,8 @@ pub struct App<MH: IMusicHoard> {
state: AppState<(), (), (), String, String, String>, state: AppState<(), (), (), String, String, String>,
// FIXME: is it possible to use a wrapper struct? - when state() is called return a wrapper // FIXME: is it possible to use a wrapper struct? - when state() is called return a wrapper
// around App<MH> which will contain App. // around App<MH> which will contain App.
memo: Vec<Option<usize>>, orig: Option<usize>,
memo: Vec<(Option<usize>, bool)>,
} }
impl<MH: IMusicHoard> App<MH> { impl<MH: IMusicHoard> App<MH> {
@ -157,6 +158,7 @@ impl<MH: IMusicHoard> App<MH> {
music_hoard, music_hoard,
selection, selection,
state, state,
orig: None,
memo: vec![], memo: vec![],
} }
} }
@ -248,7 +250,8 @@ impl<MH: IMusicHoard> IAppInteractBrowse for App<MH> {
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. // FIXME: this should be the entire selection - not just the artist.
self.memo = vec![self.selection.selected_artist()]; self.orig = self.selection.selected_artist();
self.memo = vec![];
self.selection self.selection
.reset_artist(self.music_hoard.get_collection()); .reset_artist(self.music_hoard.get_collection());
} }
@ -298,31 +301,36 @@ impl<MH: IMusicHoard> IAppInteractReloadPrivate for App<MH> {
} }
} }
// 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
// a character, a character should be removed. When in doubt see how Emacs's isearch works.
// FIXME: Also add a `cancel_search` which returns to the previous selection. // FIXME: Also add a `cancel_search` which returns to the previous selection.
impl<MH: IMusicHoard> IAppInteractSearch for App<MH> { impl<MH: IMusicHoard> IAppInteractSearch for App<MH> {
fn append_character(&mut self, ch: char) { fn append_character(&mut self, ch: char) {
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, false); let prev = self
self.memo.push(prev); .selection
.incremental_artist_search(collection, search, false);
self.memo.push((prev, true));
} }
fn search_next(&mut self) { fn search_next(&mut self) {
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();
let prev = self.selection.incremental_artist_search(collection, search, true); if !search.is_empty() {
self.memo.push(prev); let prev = self
.selection
.incremental_artist_search(collection, search, true);
self.memo.push((prev, false));
}
} }
fn remove_character(&mut self) { fn step_back(&mut self) {
let collection = self.music_hoard.get_collection(); let collection = self.music_hoard.get_collection();
if let Some((prev, pop_char)) = self.memo.pop() {
if pop_char {
let search = self.state.as_mut().unwrap_search(); let search = self.state.as_mut().unwrap_search();
if search.pop().is_some() { search.pop();
let prev = self.memo.pop().unwrap(); }
self.selection.select_artist(collection, prev); self.selection.select_artist(collection, prev);
} }
} }

View File

@ -110,7 +110,8 @@ impl Selection {
artist_name: &str, artist_name: &str,
next: bool, next: bool,
) -> Option<usize> { ) -> Option<usize> {
self.artist.incremental_search(collection, artist_name, next) 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) {
@ -196,9 +197,11 @@ impl ArtistSelection {
} }
} }
fn select(&mut self, artists: &[Artist], mut to: Option<usize>) { fn select(&mut self, artists: &[Artist], to: Option<usize>) {
to = to.map(|i| cmp::min(i, artists.len() - 1)); match to {
self.state.list.select(to); Some(to) => self.select_to(artists, to),
None => self.state.list.select(None),
}
} }
fn select_to(&mut self, artists: &[Artist], mut to: usize) { fn select_to(&mut self, artists: &[Artist], mut to: usize) {

View File

@ -159,7 +159,7 @@ impl<APP: IAppInteract> IEventHandlerPrivate<APP> for EventHandler {
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),
KeyCode::Backspace => app.remove_character(), KeyCode::Backspace => app.step_back(),
// Return. // Return.
KeyCode::Esc | KeyCode::Enter => app.finish_search(), KeyCode::Esc | KeyCode::Enter => app.finish_search(),
// Othey keys. // Othey keys.