added a way to search through list, ref #2093

This commit is contained in:
Adhyan 2024-09-01 18:52:26 -06:00
parent 75a38fa38b
commit c4fd29541b
4 changed files with 91 additions and 4 deletions

View file

@ -55,6 +55,7 @@ fn run_bin(
} }
/// See `info_file::ExerciseInfo` /// See `info_file::ExerciseInfo`
#[derive(Debug)]
pub struct Exercise { pub struct Exercise {
pub dir: Option<&'static str>, pub dir: Option<&'static str>,
pub name: &'static str, pub name: &'static str,

View file

@ -1,4 +1,4 @@
use anyhow::{Context, Result}; use anyhow::{Context, Ok, Result};
use crossterm::{ use crossterm::{
cursor, cursor,
event::{ event::{
@ -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")? {
@ -31,9 +32,50 @@ 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; // not sure why rust analyzer thinks this is unused
list_state.search_query.clear();
return Ok(());
}
KeyCode::Char(k) => {
eprintln!("pressed while searching {:?}", curr_key);
list_state.search_query.push(k);
list_state.message.push_str("search:");
list_state.message.push_str(&list_state.search_query);
list_state.message.push_str("|");
list_state.select_if_matches_search_query();
list_state.draw(stdout)?;
continue;
}
KeyCode::Backspace => {
list_state.search_query.pop();
list_state.message.push_str("search:");
list_state.message.push_str(&list_state.search_query);
list_state.message.push_str("|");
list_state.select_if_matches_search_query();
list_state.draw(stdout)?;
continue;
}
_ => {
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(),
KeyCode::Up | KeyCode::Char('k') => list_state.select_previous(), KeyCode::Up | KeyCode::Char('k') => list_state.select_previous(),
KeyCode::Home | KeyCode::Char('g') => list_state.select_first(), KeyCode::Home | KeyCode::Char('g') => list_state.select_first(),
@ -66,9 +108,16 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
return Ok(()); return Ok(());
} }
} }
KeyCode::Char('s') | KeyCode::Char('/') => {
eprintln!("starting search");
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;
}
} }
} }
Event::Mouse(event) => match event.kind { Event::Mouse(event) => match event.kind {

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

@ -45,6 +45,7 @@ pub struct ListState<'a> {
term_height: u16, term_height: u16,
separator_line: Vec<u8>, separator_line: Vec<u8>,
show_footer: bool, show_footer: bool,
pub search_query: String,
} }
impl<'a> ListState<'a> { impl<'a> ListState<'a> {
@ -78,6 +79,7 @@ impl<'a> ListState<'a> {
term_height: 0, term_height: 0,
separator_line: Vec::new(), separator_line: Vec::new(),
show_footer: true, show_footer: true,
search_query: String::new(),
}; };
slf.set_term_size(width, height); slf.set_term_size(width, height);
@ -356,6 +358,41 @@ impl<'a> ListState<'a> {
Ok(()) Ok(())
} }
pub fn select_if_matches_search_query(&mut self) {
eprintln!("search query: {:?}", self.search_query);
let idx = self
.app_state
.exercises()
.iter()
.enumerate()
.find_map(|(i, s)| {
if s.name.contains(self.search_query.as_str()) {
Some(i)
} else {
None
}
});
eprintln!("idx: {:?}", idx);
match idx {
Some(i) => {
// ? do we need this function call?
// let exercise_ind = self.selected_to_exercise_ind(i).unwrap();
let exercise_ind = i;
self.scroll_state.set_selected(exercise_ind);
eprintln!("exercise_ind: {:?}", exercise_ind);
self.update_rows();
}
None => {
let msg = String::from("[NOT FOUND]") + &self.message.clone();
self.message.clear();
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> {