Skip to content

Commit c4fd295

Browse files
committed
added a way to search through list, ref rust-lang#2093
1 parent 75a38fa commit c4fd295

File tree

4 files changed

+91
-4
lines changed

4 files changed

+91
-4
lines changed

src/exercise.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ fn run_bin(
5555
}
5656

5757
/// See `info_file::ExerciseInfo`
58+
#[derive(Debug)]
5859
pub struct Exercise {
5960
pub dir: Option<&'static str>,
6061
pub name: &'static str,

src/list.rs

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use anyhow::{Context, Result};
1+
use anyhow::{Context, Ok, Result};
22
use crossterm::{
33
cursor,
44
event::{
@@ -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")? {
@@ -31,9 +32,50 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
3132
}
3233

3334
list_state.message.clear();
35+
36+
let curr_key = key.code;
37+
38+
if is_searching {
39+
match curr_key {
40+
KeyCode::Esc | KeyCode::Enter => {
41+
is_searching = false; // not sure why rust analyzer thinks this is unused
42+
list_state.search_query.clear();
43+
return Ok(());
44+
}
45+
KeyCode::Char(k) => {
46+
eprintln!("pressed while searching {:?}", curr_key);
47+
48+
list_state.search_query.push(k);
49+
list_state.message.push_str("search:");
50+
list_state.message.push_str(&list_state.search_query);
51+
list_state.message.push_str("|");
52+
53+
list_state.select_if_matches_search_query();
54+
55+
list_state.draw(stdout)?;
56+
continue;
57+
}
58+
KeyCode::Backspace => {
59+
list_state.search_query.pop();
60+
list_state.message.push_str("search:");
61+
list_state.message.push_str(&list_state.search_query);
62+
list_state.message.push_str("|");
63+
64+
list_state.select_if_matches_search_query();
65+
66+
list_state.draw(stdout)?;
67+
continue;
68+
}
69+
_ => {
70+
continue;
71+
}
72+
}
73+
}
3474

3575
match key.code {
36-
KeyCode::Char('q') => return Ok(()),
76+
KeyCode::Char('q') => {
77+
return Ok(());
78+
}
3779
KeyCode::Down | KeyCode::Char('j') => list_state.select_next(),
3880
KeyCode::Up | KeyCode::Char('k') => list_state.select_previous(),
3981
KeyCode::Home | KeyCode::Char('g') => list_state.select_first(),
@@ -66,9 +108,16 @@ fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()>
66108
return Ok(());
67109
}
68110
}
111+
KeyCode::Char('s') | KeyCode::Char('/') => {
112+
eprintln!("starting search");
113+
list_state.message.push_str("search:|");
114+
is_searching = true;
115+
}
69116
// Redraw to remove the message.
70117
KeyCode::Esc => (),
71-
_ => continue,
118+
_ => {
119+
continue;
120+
}
72121
}
73122
}
74123
Event::Mouse(event) => match event.kind {

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: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub struct ListState<'a> {
4545
term_height: u16,
4646
separator_line: Vec<u8>,
4747
show_footer: bool,
48+
pub search_query: String,
4849
}
4950

5051
impl<'a> ListState<'a> {
@@ -78,6 +79,7 @@ impl<'a> ListState<'a> {
7879
term_height: 0,
7980
separator_line: Vec::new(),
8081
show_footer: true,
82+
search_query: String::new(),
8183
};
8284

8385
slf.set_term_size(width, height);
@@ -356,6 +358,41 @@ impl<'a> ListState<'a> {
356358

357359
Ok(())
358360
}
361+
362+
pub fn select_if_matches_search_query(&mut self) {
363+
eprintln!("search query: {:?}", self.search_query);
364+
365+
let idx = self
366+
.app_state
367+
.exercises()
368+
.iter()
369+
.enumerate()
370+
.find_map(|(i, s)| {
371+
if s.name.contains(self.search_query.as_str()) {
372+
Some(i)
373+
} else {
374+
None
375+
}
376+
});
377+
eprintln!("idx: {:?}", idx);
378+
379+
match idx {
380+
Some(i) => {
381+
// ? do we need this function call?
382+
// let exercise_ind = self.selected_to_exercise_ind(i).unwrap();
383+
let exercise_ind = i;
384+
self.scroll_state.set_selected(exercise_ind);
385+
eprintln!("exercise_ind: {:?}", exercise_ind);
386+
self.update_rows();
387+
}
388+
None => {
389+
let msg = String::from("[NOT FOUND]") + &self.message.clone();
390+
self.message.clear();
391+
self.message.push_str(&msg);
392+
}
393+
}
394+
395+
}
359396

360397
// Return `true` if there was something to select.
361398
pub fn selected_to_current_exercise(&mut self) -> Result<bool> {

0 commit comments

Comments
 (0)