mirror of
https://github.com/rust-lang/rustlings
synced 2024-11-10 06:34:20 +00:00
Merge pull request #2098 from frroossst/main
Made the list of exercises searchable, ref #2093
This commit is contained in:
commit
20616ff954
3 changed files with 62 additions and 1 deletions
28
src/list.rs
28
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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue