Skip to content

Commit 20616ff

Browse files
authored
Merge pull request #2098 from frroossst/main
Made the list of exercises searchable, ref #2093
2 parents f696d98 + f463cf8 commit 20616ff

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

src/list.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ mod state;
2121

2222
fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> {
2323
let mut list_state = ListState::new(app_state, stdout)?;
24+
let mut is_searching = false;
2425

2526
loop {
2627
match event::read().context("Failed to read terminal event")? {
@@ -32,6 +33,29 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
3233

3334
list_state.message.clear();
3435

36+
let curr_key = key.code;
37+
38+
if is_searching {
39+
match curr_key {
40+
KeyCode::Esc | KeyCode::Enter => {
41+
is_searching = false;
42+
list_state.search_query.clear();
43+
}
44+
KeyCode::Char(k) => {
45+
list_state.search_query.push(k);
46+
list_state.apply_search_query();
47+
list_state.draw(stdout)?;
48+
}
49+
KeyCode::Backspace => {
50+
list_state.search_query.pop();
51+
list_state.apply_search_query();
52+
list_state.draw(stdout)?;
53+
}
54+
_ => {}
55+
}
56+
continue;
57+
}
58+
3559
match key.code {
3660
KeyCode::Char('q') => return Ok(()),
3761
KeyCode::Down | KeyCode::Char('j') => list_state.select_next(),
@@ -66,6 +90,10 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
6690
return Ok(());
6791
}
6892
}
93+
KeyCode::Char('s' | '/') => {
94+
list_state.message.push_str("search:|");
95+
is_searching = true;
96+
}
6997
// Redraw to remove the message.
7098
KeyCode::Esc => (),
7199
_ => continue,

src/list/scroll_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl ScrollState {
4646
self.selected
4747
}
4848

49-
fn set_selected(&mut self, selected: usize) {
49+
pub fn set_selected(&mut self, selected: usize) {
5050
self.selected = Some(selected);
5151
self.update_offset();
5252
}

src/list/state.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ pub struct ListState<'a> {
4444
term_width: u16,
4545
term_height: u16,
4646
show_footer: bool,
47+
pub search_query: String,
4748
}
4849

4950
impl<'a> ListState<'a> {
@@ -76,6 +77,7 @@ impl<'a> ListState<'a> {
7677
term_width: 0,
7778
term_height: 0,
7879
show_footer: true,
80+
search_query: String::new(),
7981
};
8082

8183
slf.set_term_size(width, height);
@@ -345,6 +347,37 @@ impl<'a> ListState<'a> {
345347
Ok(())
346348
}
347349

350+
pub fn apply_search_query(&mut self) {
351+
self.message.push_str("search:");
352+
self.message.push_str(&self.search_query);
353+
self.message.push('|');
354+
355+
if self.search_query.is_empty() {
356+
return;
357+
}
358+
359+
let idx = self
360+
.app_state
361+
.exercises()
362+
.iter()
363+
.filter(|exercise| match self.filter() {
364+
Filter::None => true,
365+
Filter::Done => exercise.done,
366+
Filter::Pending => !exercise.done,
367+
})
368+
.position(|exercise| exercise.name.contains(self.search_query.as_str()));
369+
370+
match idx {
371+
Some(exercise_ind) => {
372+
self.scroll_state.set_selected(exercise_ind);
373+
}
374+
None => {
375+
let msg = String::from(" (not found)");
376+
self.message.push_str(&msg);
377+
}
378+
}
379+
}
380+
348381
// Return `true` if there was something to select.
349382
pub fn selected_to_current_exercise(&mut self) -> Result<bool> {
350383
let Some(selected) = self.scroll_state.selected() else {

0 commit comments

Comments
 (0)