mirror of
https://github.com/notohh/rustlings.git
synced 2024-11-25 14:57:32 -05:00
State -> StateFile
This commit is contained in:
parent
8c31d38fa1
commit
3bd26c7a24
4 changed files with 24 additions and 23 deletions
20
src/list.rs
20
src/list.rs
|
@ -14,7 +14,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use crate::{exercise::Exercise, state::State};
|
use crate::{exercise::Exercise, state_file::StateFile};
|
||||||
|
|
||||||
struct UiState<'a> {
|
struct UiState<'a> {
|
||||||
pub table: Table<'a>,
|
pub table: Table<'a>,
|
||||||
|
@ -25,7 +25,7 @@ struct UiState<'a> {
|
||||||
|
|
||||||
impl<'a> UiState<'a> {
|
impl<'a> UiState<'a> {
|
||||||
pub fn rows<'s, 'i>(
|
pub fn rows<'s, 'i>(
|
||||||
state: &'s State,
|
state_file: &'s StateFile,
|
||||||
exercises: &'a [Exercise],
|
exercises: &'a [Exercise],
|
||||||
) -> impl Iterator<Item = Row<'a>> + 'i
|
) -> impl Iterator<Item = Row<'a>> + 'i
|
||||||
where
|
where
|
||||||
|
@ -34,10 +34,10 @@ impl<'a> UiState<'a> {
|
||||||
{
|
{
|
||||||
exercises
|
exercises
|
||||||
.iter()
|
.iter()
|
||||||
.zip(state.progress())
|
.zip(state_file.progress())
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(ind, (exercise, done))| {
|
.map(|(ind, (exercise, done))| {
|
||||||
let next = if ind == state.next_exercise_ind() {
|
let next = if ind == state_file.next_exercise_ind() {
|
||||||
">>>>".bold().red()
|
">>>>".bold().red()
|
||||||
} else {
|
} else {
|
||||||
Span::default()
|
Span::default()
|
||||||
|
@ -58,7 +58,7 @@ impl<'a> UiState<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(state: &State, exercises: &'a [Exercise]) -> Self {
|
pub fn new(state_file: &StateFile, exercises: &'a [Exercise]) -> Self {
|
||||||
let header = Row::new(["Next", "State", "Name", "Path"]);
|
let header = Row::new(["Next", "State", "Name", "Path"]);
|
||||||
|
|
||||||
let max_name_len = exercises
|
let max_name_len = exercises
|
||||||
|
@ -74,7 +74,7 @@ impl<'a> UiState<'a> {
|
||||||
Constraint::Fill(1),
|
Constraint::Fill(1),
|
||||||
];
|
];
|
||||||
|
|
||||||
let rows = Self::rows(state, exercises);
|
let rows = Self::rows(state_file, exercises);
|
||||||
|
|
||||||
let table = Table::new(rows, widths)
|
let table = Table::new(rows, widths)
|
||||||
.header(header)
|
.header(header)
|
||||||
|
@ -147,7 +147,7 @@ impl<'a> UiState<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list(state: &mut State, exercises: &[Exercise]) -> Result<()> {
|
pub fn list(state_file: &mut StateFile, exercises: &[Exercise]) -> Result<()> {
|
||||||
let mut stdout = io::stdout().lock();
|
let mut stdout = io::stdout().lock();
|
||||||
stdout.execute(EnterAlternateScreen)?;
|
stdout.execute(EnterAlternateScreen)?;
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
|
@ -155,7 +155,7 @@ pub fn list(state: &mut State, exercises: &[Exercise]) -> Result<()> {
|
||||||
let mut terminal = Terminal::new(CrosstermBackend::new(&mut stdout))?;
|
let mut terminal = Terminal::new(CrosstermBackend::new(&mut stdout))?;
|
||||||
terminal.clear()?;
|
terminal.clear()?;
|
||||||
|
|
||||||
let mut ui_state = UiState::new(state, exercises);
|
let mut ui_state = UiState::new(state_file, exercises);
|
||||||
|
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
terminal.draw(|frame| ui_state.draw(frame))?;
|
terminal.draw(|frame| ui_state.draw(frame))?;
|
||||||
|
@ -183,8 +183,8 @@ pub fn list(state: &mut State, exercises: &[Exercise]) -> Result<()> {
|
||||||
KeyCode::Home | KeyCode::Char('g') => ui_state.select_first(),
|
KeyCode::Home | KeyCode::Char('g') => ui_state.select_first(),
|
||||||
KeyCode::End | KeyCode::Char('G') => ui_state.select_last(),
|
KeyCode::End | KeyCode::Char('G') => ui_state.select_last(),
|
||||||
KeyCode::Char('c') => {
|
KeyCode::Char('c') => {
|
||||||
state.set_next_exercise_ind(ui_state.selected)?;
|
state_file.set_next_exercise_ind(ui_state.selected)?;
|
||||||
ui_state.table = ui_state.table.rows(UiState::rows(state, exercises));
|
ui_state.table = ui_state.table.rows(UiState::rows(state_file, exercises));
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,11 +1,6 @@
|
||||||
use crate::consts::WELCOME;
|
|
||||||
use crate::embedded::{WriteStrategy, EMBEDDED_FILES};
|
|
||||||
use crate::exercise::{Exercise, ExerciseList};
|
|
||||||
use crate::run::run;
|
|
||||||
use crate::verify::verify;
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use state::State;
|
use state_file::StateFile;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use verify::VerifyState;
|
use verify::VerifyState;
|
||||||
|
@ -16,10 +11,16 @@ mod exercise;
|
||||||
mod init;
|
mod init;
|
||||||
mod list;
|
mod list;
|
||||||
mod run;
|
mod run;
|
||||||
mod state;
|
mod state_file;
|
||||||
mod verify;
|
mod verify;
|
||||||
mod watch;
|
mod watch;
|
||||||
|
|
||||||
|
use crate::consts::WELCOME;
|
||||||
|
use crate::embedded::{WriteStrategy, EMBEDDED_FILES};
|
||||||
|
use crate::exercise::{Exercise, ExerciseList};
|
||||||
|
use crate::run::run;
|
||||||
|
use crate::verify::verify;
|
||||||
|
|
||||||
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(version)]
|
#[command(version)]
|
||||||
|
@ -85,7 +86,7 @@ If you are just starting with Rustlings, run the command `rustlings init` to ini
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut state = State::read_or_default(&exercises);
|
let mut state = StateFile::read_or_default(&exercises);
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
None | Some(Subcommands::Watch) => {
|
None | Some(Subcommands::Watch) => {
|
||||||
|
|
|
@ -5,12 +5,12 @@ use std::fs;
|
||||||
use crate::exercise::Exercise;
|
use crate::exercise::Exercise;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct State {
|
pub struct StateFile {
|
||||||
next_exercise_ind: usize,
|
next_exercise_ind: usize,
|
||||||
progress: Vec<bool>,
|
progress: Vec<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl StateFile {
|
||||||
fn read(exercises: &[Exercise]) -> Option<Self> {
|
fn read(exercises: &[Exercise]) -> Option<Self> {
|
||||||
let file_content = fs::read(".rustlings.json").ok()?;
|
let file_content = fs::read(".rustlings.json").ok()?;
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
exercise::{self, Exercise},
|
exercise::{self, Exercise},
|
||||||
state::State,
|
state_file::StateFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Event {
|
enum Event {
|
||||||
|
@ -151,14 +151,14 @@ You can keep working on this exercise or jump into the next one by removing the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn watch(state: &State, exercises: &[Exercise]) -> Result<()> {
|
pub fn watch(state_file: &StateFile, exercises: &[Exercise]) -> Result<()> {
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let mut debouncer = new_debouncer(Duration::from_secs(1), tx)?;
|
let mut debouncer = new_debouncer(Duration::from_secs(1), tx)?;
|
||||||
debouncer
|
debouncer
|
||||||
.watcher()
|
.watcher()
|
||||||
.watch(Path::new("exercises"), RecursiveMode::Recursive)?;
|
.watch(Path::new("exercises"), RecursiveMode::Recursive)?;
|
||||||
|
|
||||||
let current_exercise_ind = state.next_exercise_ind();
|
let current_exercise_ind = state_file.next_exercise_ind();
|
||||||
|
|
||||||
let exercise = &exercises[current_exercise_ind];
|
let exercise = &exercises[current_exercise_ind];
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue