mirror of
https://github.com/rust-lang/rustlings.git
synced 2024-12-25 00:00:05 +03:00
feat: Add reset command, given a filename
This commit is contained in:
parent
d0c7b06eff
commit
6f44cb1dd2
78
src/main.rs
78
src/main.rs
|
@ -1,7 +1,10 @@
|
||||||
use crate::exercise::{Exercise, ExerciseList};
|
|
||||||
use crate::project::RustAnalyzerProject;
|
use crate::project::RustAnalyzerProject;
|
||||||
use crate::run::run;
|
use crate::run::run;
|
||||||
use crate::verify::verify;
|
use crate::verify::verify;
|
||||||
|
use crate::{
|
||||||
|
exercise::{Exercise, ExerciseList},
|
||||||
|
run::reset,
|
||||||
|
};
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
use console::Emoji;
|
use console::Emoji;
|
||||||
use notify::DebouncedEvent;
|
use notify::DebouncedEvent;
|
||||||
|
@ -47,6 +50,7 @@ enum Subcommands {
|
||||||
Verify(VerifyArgs),
|
Verify(VerifyArgs),
|
||||||
Watch(WatchArgs),
|
Watch(WatchArgs),
|
||||||
Run(RunArgs),
|
Run(RunArgs),
|
||||||
|
Reset(ResetArgs),
|
||||||
Hint(HintArgs),
|
Hint(HintArgs),
|
||||||
List(ListArgs),
|
List(ListArgs),
|
||||||
Lsp(LspArgs),
|
Lsp(LspArgs),
|
||||||
|
@ -71,6 +75,15 @@ struct RunArgs {
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
#[argh(subcommand, name = "reset")]
|
||||||
|
/// Resets a single exercise
|
||||||
|
struct ResetArgs {
|
||||||
|
#[argh(positional)]
|
||||||
|
/// the name of the exercise
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand, name = "hint")]
|
#[argh(subcommand, name = "hint")]
|
||||||
/// Returns a hint for the given exercise
|
/// Returns a hint for the given exercise
|
||||||
|
@ -85,7 +98,6 @@ struct HintArgs {
|
||||||
/// Enable rust-analyzer for exercises
|
/// Enable rust-analyzer for exercises
|
||||||
struct LspArgs {}
|
struct LspArgs {}
|
||||||
|
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
#[argh(subcommand, name = "list")]
|
#[argh(subcommand, name = "list")]
|
||||||
/// Lists the exercises available in Rustlings
|
/// Lists the exercises available in Rustlings
|
||||||
|
@ -164,7 +176,9 @@ fn main() {
|
||||||
"Pending"
|
"Pending"
|
||||||
};
|
};
|
||||||
let solve_cond = {
|
let solve_cond = {
|
||||||
(e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved)
|
(e.looks_done() && subargs.solved)
|
||||||
|
|| (!e.looks_done() && subargs.unsolved)
|
||||||
|
|| (!subargs.solved && !subargs.unsolved)
|
||||||
};
|
};
|
||||||
if solve_cond && (filter_cond || subargs.filter.is_none()) {
|
if solve_cond && (filter_cond || subargs.filter.is_none()) {
|
||||||
let line = if subargs.paths {
|
let line = if subargs.paths {
|
||||||
|
@ -205,6 +219,12 @@ fn main() {
|
||||||
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
|
run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Subcommands::Reset(subargs) => {
|
||||||
|
let exercise = find_exercise(&subargs.name, &exercises);
|
||||||
|
|
||||||
|
reset(exercise).unwrap_or_else(|_| std::process::exit(1));
|
||||||
|
}
|
||||||
|
|
||||||
Subcommands::Hint(subargs) => {
|
Subcommands::Hint(subargs) => {
|
||||||
let exercise = find_exercise(&subargs.name, &exercises);
|
let exercise = find_exercise(&subargs.name, &exercises);
|
||||||
|
|
||||||
|
@ -212,7 +232,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Subcommands::Verify(_subargs) => {
|
Subcommands::Verify(_subargs) => {
|
||||||
verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1));
|
verify(&exercises, (0, exercises.len()), verbose)
|
||||||
|
.unwrap_or_else(|_| std::process::exit(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
Subcommands::Lsp(_subargs) => {
|
Subcommands::Lsp(_subargs) => {
|
||||||
|
@ -236,12 +257,18 @@ fn main() {
|
||||||
|
|
||||||
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
|
Subcommands::Watch(_subargs) => match watch(&exercises, verbose) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error: Could not watch your progress. Error message was {:?}.", e);
|
println!(
|
||||||
|
"Error: Could not watch your progress. Error message was {:?}.",
|
||||||
|
e
|
||||||
|
);
|
||||||
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
|
println!("Most likely you've run out of disk space or your 'inotify limit' has been reached.");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
Ok(WatchStatus::Finished) => {
|
Ok(WatchStatus::Finished) => {
|
||||||
println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("🎉", "★"));
|
println!(
|
||||||
|
"{emoji} All exercises completed! {emoji}",
|
||||||
|
emoji = Emoji("🎉", "★")
|
||||||
|
);
|
||||||
println!("\n{}\n", FENISH_LINE);
|
println!("\n{}\n", FENISH_LINE);
|
||||||
}
|
}
|
||||||
Ok(WatchStatus::Unfinished) => {
|
Ok(WatchStatus::Unfinished) => {
|
||||||
|
@ -252,8 +279,10 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_watch_shell(
|
||||||
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_quit: Arc<AtomicBool>) {
|
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
|
||||||
|
should_quit: Arc<AtomicBool>,
|
||||||
|
) {
|
||||||
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
||||||
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
|
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
|
@ -290,16 +319,22 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>, should_q
|
||||||
|
|
||||||
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
|
||||||
if name.eq("next") {
|
if name.eq("next") {
|
||||||
exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| {
|
exercises
|
||||||
println!("🎉 Congratulations! You have done all the exercises!");
|
.iter()
|
||||||
println!("🔚 There are no more exercises to do next!");
|
.find(|e| !e.looks_done())
|
||||||
std::process::exit(1)
|
.unwrap_or_else(|| {
|
||||||
})
|
println!("🎉 Congratulations! You have done all the exercises!");
|
||||||
|
println!("🔚 There are no more exercises to do next!");
|
||||||
|
std::process::exit(1)
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
exercises.iter().find(|e| e.name == name).unwrap_or_else(|| {
|
exercises
|
||||||
println!("No exercise found for '{}'!", name);
|
.iter()
|
||||||
std::process::exit(1)
|
.find(|e| e.name == name)
|
||||||
})
|
.unwrap_or_else(|| {
|
||||||
|
println!("No exercise found for '{}'!", name);
|
||||||
|
std::process::exit(1)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,8 +372,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<WatchStatus> {
|
||||||
let filepath = b.as_path().canonicalize().unwrap();
|
let filepath = b.as_path().canonicalize().unwrap();
|
||||||
let pending_exercises = exercises
|
let pending_exercises = exercises
|
||||||
.iter()
|
.iter()
|
||||||
.find(|e| filepath.ends_with(&e.path)).into_iter()
|
.find(|e| filepath.ends_with(&e.path))
|
||||||
.chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
|
.into_iter()
|
||||||
|
.chain(
|
||||||
|
exercises
|
||||||
|
.iter()
|
||||||
|
.filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
|
||||||
|
);
|
||||||
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
|
let num_done = exercises.iter().filter(|e| e.looks_done()).count();
|
||||||
clear_screen();
|
clear_screen();
|
||||||
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
|
match verify(pending_exercises, (num_done, exercises.len()), verbose) {
|
||||||
|
|
15
src/run.rs
15
src/run.rs
|
@ -1,3 +1,5 @@
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::exercise::{Exercise, Mode};
|
use crate::exercise::{Exercise, Mode};
|
||||||
use crate::verify::test;
|
use crate::verify::test;
|
||||||
use indicatif::ProgressBar;
|
use indicatif::ProgressBar;
|
||||||
|
@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resets the exercise by stashing the changes.
|
||||||
|
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
|
||||||
|
let command = Command::new("git")
|
||||||
|
.args(["stash", "--"])
|
||||||
|
.arg(&exercise.path)
|
||||||
|
.spawn();
|
||||||
|
|
||||||
|
match command {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Invoke the rust compiler on the path of the given exercise
|
// Invoke the rust compiler on the path of the given exercise
|
||||||
// and run the ensuing binary.
|
// and run the ensuing binary.
|
||||||
// This is strictly for non-test binaries, so output is displayed
|
// This is strictly for non-test binaries, so output is displayed
|
||||||
|
|
Loading…
Reference in a new issue