diff --git a/.all-contributorsrc b/.all-contributorsrc
index 03e8dd1c..d18743c2 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -957,6 +957,51 @@
"content",
"code"
]
+ },
+ {
+ "login": "granddaifuku",
+ "name": "granddaifuku",
+ "avatar_url": "https://avatars.githubusercontent.com/u/49578068?v=4",
+ "profile": "https://granddaifuku.com/",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "Weilet",
+ "name": "Weilet",
+ "avatar_url": "https://avatars.githubusercontent.com/u/32561597?v=4",
+ "profile": "https://weilet.me",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "Millione",
+ "name": "LIU JIE",
+ "avatar_url": "https://avatars.githubusercontent.com/u/38575932?v=4",
+ "profile": "https://github.com/Millione",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "abusch",
+ "name": "Antoine BΓΌsch",
+ "avatar_url": "https://avatars.githubusercontent.com/u/506344?v=4",
+ "profile": "https://github.com/abusch",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "frogtd",
+ "name": "frogtd",
+ "avatar_url": "https://avatars.githubusercontent.com/u/31412003?v=4",
+ "profile": "https://frogtd.com/",
+ "contributions": [
+ "content"
+ ]
}
],
"contributorsPerLine": 8,
diff --git a/.gitignore b/.gitignore
index 06de8710..253f8f33 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ exercises/clippy/Cargo.toml
exercises/clippy/Cargo.lock
.idea
.vscode
+*.iml
diff --git a/README.md b/README.md
index 608bba9b..ac1d84d3 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-[](#contributors-)
+[](#contributors-)
# rustlings π¦β€οΈ
@@ -305,6 +305,13 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
 Damian π |
 Ben Armstead π» |
 anuk909 π π» |
+  granddaifuku π |
+
+
+  Weilet π |
+  LIU JIE π |
+  Antoine BΓΌsch π» |
+  frogtd π |
diff --git a/exercises/modules/modules2.rs b/exercises/modules/modules2.rs
index 687bb788..87f0c458 100644
--- a/exercises/modules/modules2.rs
+++ b/exercises/modules/modules2.rs
@@ -1,13 +1,13 @@
// modules2.rs
// You can bring module paths into scopes and provide new names for them with the
-// 'use' and 'as' keywords. Fix these 'use' statments to make the code compile.
+// 'use' and 'as' keywords. Fix these 'use' statements to make the code compile.
// Make me compile! Execute `rustlings hint modules2` for hints :)
// I AM NOT DONE
mod delicious_snacks {
- // TODO: Fix these use statments
+ // TODO: Fix these use statements
use self::fruits::PEAR as ???
use self::veggies::CUCUMBER as ???
diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs
index 9c1d089a..7de4c1fc 100644
--- a/exercises/quiz1.rs
+++ b/exercises/quiz1.rs
@@ -7,8 +7,7 @@
// more than 40 at once, each apple only costs 1! Write a function that calculates
// the price of an order of apples given the quantity bought. No hints this time!
-// Put your function here!
-// fn ..... {
+// Put your function here!// fn ..... {
fn calculate_apple_price(quantity:i32) -> i32 {
if quantity > 40 {
return quantity * 1;
@@ -16,6 +15,7 @@ fn calculate_apple_price(quantity:i32) -> i32 {
return quantity * 2;
}
}
+// fn calculate_apple_price {
// Don't modify this function!
#[test]
diff --git a/src/exercise.rs b/src/exercise.rs
index 53457ace..ec694df9 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -133,7 +133,7 @@ path = "{}.rs""#,
"Failed to write π Clippy π Cargo.toml file."
};
fs::write(CLIPPY_CARGO_TOML_PATH, cargo_toml).expect(cargo_toml_error_msg);
- // To support the ability to run the clipy exercises, build
+ // To support the ability to run the clippy exercises, build
// an executable, in addition to running clippy. With a
// compilation failure, this would silently fail. But we expect
// clippy to reflect the same failure while compiling later.
diff --git a/src/main.rs b/src/main.rs
index 1e343478..30096dfe 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,7 +10,8 @@ use std::fs;
use std::io::{self, prelude::*};
use std::path::Path;
use std::process::{Command, Stdio};
-use std::sync::mpsc::channel;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::mpsc::{RecvTimeoutError, channel};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
@@ -217,65 +218,85 @@ fn main() {
}
Subcommands::Watch(_subargs) => {
- if let Err(e) = watch(&exercises, verbose) {
- 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.");
- std::process::exit(1);
+ match watch(&exercises, verbose) {
+ Err(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.");
+ std::process::exit(1);
+ }
+ Ok(WatchStatus::Finished) => {
+ println!(
+ "{emoji} All exercises completed! {emoji}",
+ emoji = Emoji("π", "β
")
+ );
+ println!();
+ println!("+----------------------------------------------------+");
+ println!("| You made it to the Fe-nish line! |");
+ println!("+-------------------------- ------------------------+");
+ println!(" \\/ ");
+ println!(" ββ ββββββββ ββββββββ ββ ");
+ println!(" ββββ ββ ββ ββ ββ ββ ββ ββββ ");
+ println!(" ββββ ββ ββ ββ ββ ββ ββββ ");
+ println!(" ββββββββββ ββ ββ ββ ββββββββ ");
+ println!(" ββββββββ ββ ββββ ββ ββββ ββ ββββββββ ");
+ println!(" ββββ ββ ββββ ββ ββββ ββββ ββββ ");
+ println!(" ββ ββββββ ββββββ ββββββ ββ ");
+ println!(" ββββββββββββββββββββββββββββββββββββββ ");
+ println!(" ββββββββββββββββββββββββββββββββββ ");
+ println!(" ββββββββββββββββββββββββββββββ ");
+ println!(" ββ ββββββββββββββββββββββββββ ββ ");
+ println!(" ββ ββββββββββββββββββββββββββ ββ ");
+ println!(" ββ ββ ββββββββββββββββββ ββ ββ ");
+ println!(" ββ ββ ββ ββ ββ ββ ");
+ println!(" ββ ββ ββ ββ ");
+ println!();
+ println!("We hope you enjoyed learning about the various aspects of Rust!");
+ println!(
+ "If you noticed any issues, please don't hesitate to report them to our repo."
+ );
+ println!("You can also contribute your own exercises to help the greater community!");
+ println!();
+ println!("Before reporting an issue or contributing, please read our guidelines:");
+ println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
+ }
+ Ok(WatchStatus::Unfinished) => {
+ println!("We hope you're enjoying learning about Rust!");
+ println!("If you want to continue working on the exercises at a later point, you can simply run `rustlings watch` again");
+ }
}
- println!(
- "{emoji} All exercises completed! {emoji}",
- emoji = Emoji("π", "β
")
- );
- println!();
- println!("+----------------------------------------------------+");
- println!("| You made it to the Fe-nish line! |");
- println!("+-------------------------- ------------------------+");
- println!(" \\/ ");
- println!(" ββ ββββββββ ββββββββ ββ ");
- println!(" ββββ ββ ββ ββ ββ ββ ββ ββββ ");
- println!(" ββββ ββ ββ ββ ββ ββ ββββ ");
- println!(" ββββββββββ ββ ββ ββ ββββββββ ");
- println!(" ββββββββ ββ ββββ ββ ββββ ββ ββββββββ ");
- println!(" ββββ ββ ββββ ββ ββββ ββββ ββββ ");
- println!(" ββ ββββββ ββββββ ββββββ ββ ");
- println!(" ββββββββββββββββββββββββββββββββββββββ ");
- println!(" ββββββββββββββββββββββββββββββββββ ");
- println!(" ββββββββββββββββββββββββββββββ ");
- println!(" ββ ββββββββββββββββββββββββββ ββ ");
- println!(" ββ ββββββββββββββββββββββββββ ββ ");
- println!(" ββ ββ ββββββββββββββββββ ββ ββ ");
- println!(" ββ ββ ββ ββ ββ ββ ");
- println!(" ββ ββ ββ ββ ");
- println!();
- println!("We hope you enjoyed learning about the various aspects of Rust!");
- println!(
- "If you noticed any issues, please don't hesitate to report them to our repo."
- );
- println!("You can also contribute your own exercises to help the greater community!");
- println!();
- println!("Before reporting an issue or contributing, please read our guidelines:");
- println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
}
}
}
-fn spawn_watch_shell(failed_exercise_hint: &Arc>>) {
+fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_quit: Arc) {
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
- println!("Type 'hint' or open the corresponding README.md file to get help or type 'clear' to clear the screen.");
+ println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
thread::spawn(move || loop {
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => {
let input = input.trim();
- if input.eq("hint") {
+ if input == "hint" {
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
println!("{}", hint);
}
- } else if input.eq("clear") {
+ } else if input == "clear" {
println!("\x1B[2J\x1B[1;1H");
+ } else if input.eq("quit") {
+ should_quit.store(true, Ordering::SeqCst);
+ println!("Bye!");
+ } else if input.eq("help") {
+ println!("Commands available to you in watch mode:");
+ println!(" hint - prints the current exercise's hint");
+ println!(" clear - clears the screen");
+ println!(" quit - quits watch mode");
+ println!(" help - displays this help message");
+ println!();
+ println!("Watch mode automatically re-evaluates the current exercise");
+ println!("when you edit a file's contents.")
} else {
println!("unknown command: {}", input);
}
@@ -306,7 +327,12 @@ fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise {
}
}
-fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
+enum WatchStatus {
+ Finished,
+ Unfinished,
+}
+
+fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result {
/* Clears the terminal with an ANSI escape code.
Works in UNIX and newer Windows terminals. */
fn clear_screen() {
@@ -314,6 +340,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
}
let (tx, rx) = channel();
+ let should_quit = Arc::new(AtomicBool::new(false));
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
@@ -322,12 +349,12 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
let failed_exercise_hint = match verify(exercises.iter(), verbose) {
- Ok(_) => return Ok(()),
+ Ok(_) => return Ok(WatchStatus::Finished),
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
};
- spawn_watch_shell(&failed_exercise_hint);
+ spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit));
loop {
- match rx.recv() {
+ match rx.recv_timeout(Duration::from_secs(1)) {
Ok(event) => match event {
DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
if b.extension() == Some(OsStr::new("rs")) && b.exists() {
@@ -343,7 +370,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
);
clear_screen();
match verify(pending_exercises, verbose) {
- Ok(_) => return Ok(()),
+ Ok(_) => return Ok(WatchStatus::Finished),
Err(exercise) => {
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
*failed_exercise_hint = Some(to_owned_hint(exercise));
@@ -353,8 +380,15 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result<()> {
}
_ => {}
},
+ Err(RecvTimeoutError::Timeout) => {
+ // the timeout expired, just check the `should_quit` variable below then loop again
+ }
Err(e) => println!("watch error: {:?}", e),
}
+ // Check if we need to exit
+ if should_quit.load(Ordering::SeqCst) {
+ return Ok(WatchStatus::Unfinished);
+ }
}
}