Merge pull request #2098 from frroossst/main

Made the list of exercises searchable, ref #2093
This commit is contained in:
Mo 2024-09-04 00:40:22 +02:00 committed by GitHub
commit 20616ff954
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 1 deletions

View file

@ -21,6 +21,7 @@ mod state;
fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> { fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> {
let mut list_state = ListState::new(app_state, stdout)?; let mut list_state = ListState::new(app_state, stdout)?;
let mut is_searching = false;
loop { loop {
match event::read().context("Failed to read terminal event")? { match event::read().context("Failed to read terminal event")? {
@ -32,6 +33,29 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
list_state.message.clear(); list_state.message.clear();
let curr_key = key.code;
if is_searching {
match curr_key {
KeyCode::Esc | KeyCode::Enter => {
is_searching = false;
list_state.search_query.clear();
}
KeyCode::Char(k) => {
list_state.search_query.push(k);
list_state.apply_search_query();
list_state.draw(stdout)?;
}
KeyCode::Backspace => {
list_state.search_query.pop();
list_state.apply_search_query();
list_state.draw(stdout)?;
}
_ => {}
}
continue;
}
match key.code { match key.code {
KeyCode::Char('q') => return Ok(()), KeyCode::Char('q') => return Ok(()),
KeyCode::Down | KeyCode::Char('j') => list_state.select_next(), KeyCode::Down | KeyCode::Char('j') => list_state.select_next(),
@ -66,6 +90,10 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
return Ok(()); return Ok(());
} }
} }
KeyCode::Char('s' | '/') => {
list_state.message.push_str("search:|");
is_searching = true;
}
// Redraw to remove the message. // Redraw to remove the message.
KeyCode::Esc => (), KeyCode::Esc => (),
_ => continue, _ => continue,

View file

@ -46,7 +46,7 @@ impl ScrollState {
self.selected self.selected
} }
fn set_selected(&mut self, selected: usize) { pub fn set_selected(&mut self, selected: usize) {
self.selected = Some(selected); self.selected = Some(selected);
self.update_offset(); self.update_offset();
} }

View file

@ -44,6 +44,7 @@ pub struct ListState<'a> {
term_width: u16, term_width: u16,
term_height: u16, term_height: u16,
show_footer: bool, show_footer: bool,
pub search_query: String,
} }
impl<'a> ListState<'a> { impl<'a> ListState<'a> {
@ -76,6 +77,7 @@ impl<'a> ListState<'a> {
term_width: 0, term_width: 0,
term_height: 0, term_height: 0,
show_footer: true, show_footer: true,
search_query: String::new(),
}; };
slf.set_term_size(width, height); slf.set_term_size(width, height);
@ -345,6 +347,37 @@ impl<'a> ListState<'a> {
Ok(()) Ok(())
} }
pub fn apply_search_query(&mut self) {
self.message.push_str("search:");
self.message.push_str(&self.search_query);
self.message.push('|');
if self.search_query.is_empty() {
return;
}
let idx = self
.app_state
.exercises()
.iter()
.filter(|exercise| match self.filter() {
Filter::None => true,
Filter::Done => exercise.done,
Filter::Pending => !exercise.done,
})
.position(|exercise| exercise.name.contains(self.search_query.as_str()));
match idx {
Some(exercise_ind) => {
self.scroll_state.set_selected(exercise_ind);
}
None => {
let msg = String::from(" (not found)");
self.message.push_str(&msg);
}
}
}
// Return `true` if there was something to select. // Return `true` if there was something to select.
pub fn selected_to_current_exercise(&mut self) -> Result<bool> { pub fn selected_to_current_exercise(&mut self) -> Result<bool> {
let Some(selected) = self.scroll_state.selected() else { let Some(selected) = self.scroll_state.selected() else {