summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMo <76752051+mo8it@users.noreply.github.com>2024-09-04 00:40:22 +0200
committerGitHub <noreply@github.com>2024-09-04 00:40:22 +0200
commit20616ff954f19551b7a421193ed915fa9a518915 (patch)
tree9b7546034a6a6032ff20b3027f5b6db1e0c4fd3e /src
parentf696d9827023af13489015db8b9f3ab4fce6fee5 (diff)
parentf463cf86627411696922bd703e8c875eec7b367b (diff)
Merge pull request #2098 from frroossst/main
Made the list of exercises searchable, ref #2093
Diffstat (limited to 'src')
-rw-r--r--src/list.rs28
-rw-r--r--src/list/scroll_state.rs2
-rw-r--r--src/list/state.rs33
3 files changed, 62 insertions, 1 deletions
diff --git a/src/list.rs b/src/list.rs
index 481fb2f..5d7c8dd 100644
--- a/src/list.rs
+++ b/src/list.rs
@@ -21,6 +21,7 @@ mod state;
fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> {
let mut list_state = ListState::new(app_state, stdout)?;
+ let mut is_searching = false;
loop {
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();
+ 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 {
KeyCode::Char('q') => return Ok(()),
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(());
}
}
+ KeyCode::Char('s' | '/') => {
+ list_state.message.push_str("search:|");
+ is_searching = true;
+ }
// Redraw to remove the message.
KeyCode::Esc => (),
_ => continue,
diff --git a/src/list/scroll_state.rs b/src/list/scroll_state.rs
index 25a7373..2c02ed4 100644
--- a/src/list/scroll_state.rs
+++ b/src/list/scroll_state.rs
@@ -46,7 +46,7 @@ impl ScrollState {
self.selected
}
- fn set_selected(&mut self, selected: usize) {
+ pub fn set_selected(&mut self, selected: usize) {
self.selected = Some(selected);
self.update_offset();
}
diff --git a/src/list/state.rs b/src/list/state.rs
index 7a2d3bf..60077c7 100644
--- a/src/list/state.rs
+++ b/src/list/state.rs
@@ -44,6 +44,7 @@ pub struct ListState<'a> {
term_width: u16,
term_height: u16,
show_footer: bool,
+ pub search_query: String,
}
impl<'a> ListState<'a> {
@@ -76,6 +77,7 @@ impl<'a> ListState<'a> {
term_width: 0,
term_height: 0,
show_footer: true,
+ search_query: String::new(),
};
slf.set_term_size(width, height);
@@ -345,6 +347,37 @@ impl<'a> ListState<'a> {
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.
pub fn selected_to_current_exercise(&mut self) -> Result<bool> {
let Some(selected) = self.scroll_state.selected() else {