diff options
| -rw-r--r-- | src/list.rs | 54 | ||||
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | src/state.rs | 31 | ||||
| -rw-r--r-- | src/watch.rs | 2 |
4 files changed, 59 insertions, 32 deletions
diff --git a/src/list.rs b/src/list.rs index ff031cb..bb5ba1c 100644 --- a/src/list.rs +++ b/src/list.rs @@ -16,25 +16,13 @@ use std::io; use crate::{exercise::Exercise, state::State}; -fn table<'a>(state: &State, exercises: &'a [Exercise]) -> Table<'a> { - let header = Row::new(["Next", "State", "Name", "Path"]); - - let max_name_len = exercises +fn rows<'s, 'e>(state: &'s State, exercises: &'e [Exercise]) -> impl Iterator<Item = Row<'e>> + 's +where + 'e: 's, +{ + exercises .iter() - .map(|exercise| exercise.name.len()) - .max() - .unwrap_or(4) as u16; - - let widths = [ - Constraint::Length(4), - Constraint::Length(7), - Constraint::Length(max_name_len), - Constraint::Fill(1), - ]; - - let rows = exercises - .iter() - .zip(&state.progress) + .zip(state.progress()) .enumerate() .map(|(ind, (exercise, done))| { let exercise_state = if *done { @@ -43,7 +31,7 @@ fn table<'a>(state: &State, exercises: &'a [Exercise]) -> Table<'a> { "PENDING".yellow() }; - let next = if ind == state.next_exercise_ind { + let next = if ind == state.next_exercise_ind() { ">>>>".bold().red() } else { Span::default() @@ -56,9 +44,25 @@ fn table<'a>(state: &State, exercises: &'a [Exercise]) -> Table<'a> { Span::raw(exercise.path.to_string_lossy()), ]) }) - .collect::<Vec<_>>(); +} - Table::new(rows, widths) +fn table<'a>(state: &State, exercises: &'a [Exercise]) -> Table<'a> { + let header = Row::new(["Next", "State", "Name", "Path"]); + + let max_name_len = exercises + .iter() + .map(|exercise| exercise.name.len()) + .max() + .unwrap_or(4) as u16; + + let widths = [ + Constraint::Length(4), + Constraint::Length(7), + Constraint::Length(max_name_len), + Constraint::Fill(1), + ]; + + Table::new(rows(state, exercises), widths) .header(header) .column_spacing(2) .highlight_spacing(HighlightSpacing::Always) @@ -67,7 +71,7 @@ fn table<'a>(state: &State, exercises: &'a [Exercise]) -> Table<'a> { .block(Block::default().borders(Borders::BOTTOM)) } -pub fn list(state: &State, exercises: &[Exercise]) -> Result<()> { +pub fn list(state: &mut State, exercises: &[Exercise]) -> Result<()> { let mut stdout = io::stdout().lock(); stdout.execute(EnterAlternateScreen)?; @@ -76,7 +80,7 @@ pub fn list(state: &State, exercises: &[Exercise]) -> Result<()> { let mut terminal = Terminal::new(CrosstermBackend::new(&mut stdout))?; terminal.clear()?; - let table = table(state, exercises); + let mut table = table(state, exercises); let last_ind = exercises.len() - 1; let mut selected = 0; @@ -143,6 +147,10 @@ pub fn list(state: &State, exercises: &[Exercise]) -> Result<()> { selected = last_ind; table_state.select(Some(selected)); } + KeyCode::Char('c') => { + state.set_next_exercise_ind(selected)?; + table = table.rows(rows(state, exercises)); + } _ => (), } } diff --git a/src/main.rs b/src/main.rs index 34d1784..e82fc80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -85,7 +85,7 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini exit(1); } - let state = State::read_or_default(&exercises); + let mut state = State::read_or_default(&exercises); match args.command { None | Some(Subcommands::Watch) => { @@ -94,7 +94,7 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini // `Init` is handled above. Some(Subcommands::Init) => (), Some(Subcommands::List) => { - list::list(&state, &exercises)?; + list::list(&mut state, &exercises)?; } Some(Subcommands::Run { name }) => { let exercise = find_exercise(&name, &exercises)?; diff --git a/src/state.rs b/src/state.rs index f29dc13..5a64487 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; use std::fs; @@ -6,8 +6,8 @@ use crate::exercise::Exercise; #[derive(Serialize, Deserialize)] pub struct State { - pub next_exercise_ind: usize, - pub progress: Vec<bool>, + next_exercise_ind: usize, + progress: Vec<bool>, } impl State { @@ -30,11 +30,30 @@ impl State { }) } - pub fn write(&self) -> Result<()> { + fn write(&self) -> Result<()> { // TODO: Capacity - let mut buf = Vec::with_capacity(1 << 12); + let mut buf = Vec::with_capacity(1024); serde_json::ser::to_writer(&mut buf, self).context("Failed to serialize the state")?; - dbg!(buf.len()); + Ok(()) } + + #[inline] + pub fn next_exercise_ind(&self) -> usize { + self.next_exercise_ind + } + + pub fn set_next_exercise_ind(&mut self, ind: usize) -> Result<()> { + if ind >= self.progress.len() { + bail!("The next exercise index is higher than the number of exercises"); + } + + self.next_exercise_ind = ind; + self.write() + } + + #[inline] + pub fn progress(&self) -> &[bool] { + &self.progress + } } diff --git a/src/watch.rs b/src/watch.rs index 92da20d..cc9668d 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -158,7 +158,7 @@ pub fn watch(state: &State, exercises: &[Exercise]) -> Result<()> { .watcher() .watch(Path::new("exercises"), RecursiveMode::Recursive)?; - let current_exercise_ind = state.progress.iter().position(|done| *done).unwrap_or(0); + let current_exercise_ind = state.next_exercise_ind(); let exercise = &exercises[current_exercise_ind]; |
