2024-04-01 12:38:01 -04:00
|
|
|
use anyhow::{bail, Context, Result};
|
2023-08-25 17:18:01 -04:00
|
|
|
use clap::{Parser, Subcommand};
|
2024-04-07 18:36:26 -04:00
|
|
|
use std::{path::Path, process::exit};
|
2019-01-09 14:33:43 -05:00
|
|
|
|
2024-04-04 21:04:53 -04:00
|
|
|
mod consts;
|
2024-03-28 16:06:36 -04:00
|
|
|
mod embedded;
|
2019-04-11 16:41:24 -04:00
|
|
|
mod exercise;
|
2024-03-28 20:29:41 -04:00
|
|
|
mod init;
|
2024-04-06 21:03:37 -04:00
|
|
|
mod list;
|
2024-04-09 13:37:39 -04:00
|
|
|
mod progress_bar;
|
2019-01-09 14:33:43 -05:00
|
|
|
mod run;
|
2024-04-07 13:01:08 -04:00
|
|
|
mod state_file;
|
2019-01-09 14:33:58 -05:00
|
|
|
mod verify;
|
2024-04-06 19:17:53 -04:00
|
|
|
mod watch;
|
2018-05-14 12:41:58 -04:00
|
|
|
|
2024-04-07 18:36:26 -04:00
|
|
|
use self::{
|
|
|
|
consts::WELCOME,
|
|
|
|
exercise::{Exercise, InfoFile},
|
2024-04-09 20:12:50 -04:00
|
|
|
list::list,
|
2024-04-07 18:36:26 -04:00
|
|
|
run::run,
|
|
|
|
state_file::StateFile,
|
|
|
|
verify::{verify, VerifyState},
|
2024-04-09 20:12:50 -04:00
|
|
|
watch::{watch, WatchExit},
|
2024-04-07 18:36:26 -04:00
|
|
|
};
|
2024-04-07 13:01:08 -04:00
|
|
|
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
|
2023-08-25 17:18:01 -04:00
|
|
|
#[derive(Parser)]
|
|
|
|
#[command(version)]
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
struct Args {
|
2023-08-25 17:18:01 -04:00
|
|
|
#[command(subcommand)]
|
|
|
|
command: Option<Subcommands>,
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
}
|
|
|
|
|
2023-08-25 17:18:01 -04:00
|
|
|
#[derive(Subcommand)]
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
enum Subcommands {
|
2024-03-28 20:29:41 -04:00
|
|
|
/// Initialize Rustlings
|
|
|
|
Init,
|
2023-08-25 17:18:01 -04:00
|
|
|
/// Verify all exercises according to the recommended order
|
|
|
|
Verify,
|
2024-04-04 21:04:53 -04:00
|
|
|
/// Same as just running `rustlings` without a subcommand.
|
2024-04-04 15:06:11 -04:00
|
|
|
Watch,
|
2023-08-25 17:18:01 -04:00
|
|
|
/// Run/Test a single exercise
|
|
|
|
Run {
|
|
|
|
/// The name of the exercise
|
|
|
|
name: String,
|
|
|
|
},
|
2024-03-28 17:11:16 -04:00
|
|
|
/// Reset a single exercise
|
2023-08-25 17:18:01 -04:00
|
|
|
Reset {
|
|
|
|
/// The name of the exercise
|
|
|
|
name: String,
|
|
|
|
},
|
|
|
|
/// Return a hint for the given exercise
|
|
|
|
Hint {
|
|
|
|
/// The name of the exercise
|
|
|
|
name: String,
|
|
|
|
},
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
}
|
|
|
|
|
2024-04-09 15:16:27 -04:00
|
|
|
fn find_exercise(name: &str, exercises: &'static [Exercise]) -> Result<(usize, &'static Exercise)> {
|
2024-04-07 16:43:59 -04:00
|
|
|
if name == "next" {
|
|
|
|
for (ind, exercise) in exercises.iter().enumerate() {
|
|
|
|
if !exercise.looks_done()? {
|
|
|
|
return Ok((ind, exercise));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
println!("🎉 Congratulations! You have done all the exercises!");
|
|
|
|
println!("🔚 There are no more exercises to do next!");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
exercises
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.find(|(_, exercise)| exercise.name == name)
|
|
|
|
.with_context(|| format!("No exercise found for '{name}'!"))
|
|
|
|
}
|
|
|
|
|
2024-03-24 22:46:56 -04:00
|
|
|
fn main() -> Result<()> {
|
2023-08-25 17:18:01 -04:00
|
|
|
let args = Args::parse();
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
|
2024-03-31 12:25:54 -04:00
|
|
|
which::which("cargo").context(
|
|
|
|
"Failed to find `cargo`.
|
2024-03-31 10:55:33 -04:00
|
|
|
Did you already install Rust?
|
2024-03-31 12:25:54 -04:00
|
|
|
Try running `cargo --version` to diagnose the problem.",
|
|
|
|
)?;
|
2019-11-11 11:15:14 -05:00
|
|
|
|
2024-04-09 15:23:02 -04:00
|
|
|
let mut info_file = InfoFile::parse()?;
|
|
|
|
info_file.exercises.shrink_to_fit();
|
|
|
|
// Leaking is not a problem since the exercises' slice is used until the end of the program.
|
|
|
|
let exercises = info_file.exercises.leak();
|
2019-04-11 16:41:24 -04:00
|
|
|
|
2024-03-28 20:29:41 -04:00
|
|
|
if matches!(args.command, Some(Subcommands::Init)) {
|
2024-04-09 15:16:27 -04:00
|
|
|
init::init(exercises).context("Initialization failed")?;
|
2024-03-28 20:52:05 -04:00
|
|
|
println!(
|
|
|
|
"\nDone initialization!\n
|
|
|
|
Run `cd rustlings` to go into the generated directory.
|
|
|
|
Then run `rustlings` for further instructions on getting started."
|
|
|
|
);
|
2024-03-28 20:29:41 -04:00
|
|
|
return Ok(());
|
|
|
|
} else if !Path::new("exercises").is_dir() {
|
|
|
|
println!(
|
2024-04-06 19:17:53 -04:00
|
|
|
"
|
|
|
|
{WELCOME}
|
|
|
|
|
|
|
|
The `exercises` directory wasn't found in the current directory.
|
2024-03-28 20:52:05 -04:00
|
|
|
If you are just starting with Rustlings, run the command `rustlings init` to initialize it."
|
2024-03-28 20:29:41 -04:00
|
|
|
);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2024-04-09 15:16:27 -04:00
|
|
|
let mut state_file = StateFile::read_or_default(exercises);
|
2024-04-06 19:17:53 -04:00
|
|
|
|
2024-04-04 21:04:53 -04:00
|
|
|
match args.command {
|
2024-04-09 20:12:50 -04:00
|
|
|
None | Some(Subcommands::Watch) => loop {
|
|
|
|
match watch(&mut state_file, exercises)? {
|
|
|
|
WatchExit::Shutdown => break,
|
|
|
|
// It is much easier to exit the watch mode, launch the list mode and then restart
|
|
|
|
// the watch mode instead of trying to pause the watch threads and correct the
|
|
|
|
// watch state.
|
|
|
|
WatchExit::List => list(&mut state_file, exercises)?,
|
|
|
|
}
|
|
|
|
},
|
2024-03-28 20:29:41 -04:00
|
|
|
// `Init` is handled above.
|
2024-04-04 21:04:53 -04:00
|
|
|
Some(Subcommands::Init) => (),
|
|
|
|
Some(Subcommands::Run { name }) => {
|
2024-04-09 15:16:27 -04:00
|
|
|
let (_, exercise) = find_exercise(&name, exercises)?;
|
2024-04-04 15:06:11 -04:00
|
|
|
run(exercise).unwrap_or_else(|_| exit(1));
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
}
|
2024-04-04 21:04:53 -04:00
|
|
|
Some(Subcommands::Reset { name }) => {
|
2024-04-09 15:16:27 -04:00
|
|
|
let (ind, exercise) = find_exercise(&name, exercises)?;
|
2024-04-07 16:43:59 -04:00
|
|
|
exercise.reset()?;
|
|
|
|
state_file.reset(ind)?;
|
2024-04-07 19:33:11 -04:00
|
|
|
println!("The exercise {exercise} has been reset!");
|
2022-08-17 10:31:53 -04:00
|
|
|
}
|
2024-04-04 21:04:53 -04:00
|
|
|
Some(Subcommands::Hint { name }) => {
|
2024-04-09 15:16:27 -04:00
|
|
|
let (_, exercise) = find_exercise(&name, exercises)?;
|
feat: Replace clap with argh
I’ve been wanting to do this for a while, but always procrastinated on it. We’ve been using Clap since the 2.0 rewrite, but Clap is known to be a fairly heavy library. Since Rustlings is usually peoples’ first contact with a Rust compilation, I think it’s in our best interests that this complation is as fast as possible. In effect, replacing Clap with the smaller, structopt-style `argh` reduces the amount of crates needing to be compiled from 82 to 60.
I also think this makes the code way easier to read, we don’t need to use Clap’s methods anymore, but can switch over to using pure Rust methods, e.g., switches are booleans, options are Option<String>s or the like, and subcommands are just structs.
2021-04-20 06:46:49 -04:00
|
|
|
println!("{}", exercise.hint);
|
|
|
|
}
|
2024-04-09 15:16:27 -04:00
|
|
|
Some(Subcommands::Verify) => match verify(exercises, 0)? {
|
2024-04-01 12:38:01 -04:00
|
|
|
VerifyState::AllExercisesDone => println!("All exercises done!"),
|
|
|
|
VerifyState::Failed(exercise) => bail!("Exercise {exercise} failed"),
|
|
|
|
},
|
2018-11-26 05:10:38 -05:00
|
|
|
}
|
2024-03-24 22:46:56 -04:00
|
|
|
|
|
|
|
Ok(())
|
2018-05-06 12:59:50 -04:00
|
|
|
}
|