Auto merge of #241 - vyaslav:master, r=fmoko
feat(watch): show hint while watching `rustlings hint ...` command is not convenient when doing exercises with `rustlings watch`. This PR makes it possible for user to type `hint` while running `watch` and get hint text for exercise which is currently failing. e.g. ```rust ... --> exercises/variables/variables1.rs:13:36 | 13 | println!("x has the value {}", x); | ^ not found in this scope error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0425`. type 'hint' to get help: hint Hint: The declaration on line 12 is missing a keyword that is needed in Rust to create a new variable binding. ```
This commit is contained in:
commit
f4acb888a6
32
src/main.rs
32
src/main.rs
|
@ -6,9 +6,12 @@ use notify::DebouncedEvent;
|
||||||
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::sync::mpsc::channel;
|
use std::sync::mpsc::channel;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
mod exercise;
|
mod exercise;
|
||||||
|
@ -108,6 +111,26 @@ fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_watch_shell(failed_exercise_hint: &Arc<Mutex<Option<String>>>) {
|
||||||
|
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
|
||||||
|
println!("Type 'hint' to get help");
|
||||||
|
thread::spawn(move || loop {
|
||||||
|
let mut input = String::new();
|
||||||
|
match io::stdin().read_line(&mut input) {
|
||||||
|
Ok(_) => {
|
||||||
|
if input.trim().eq("hint") {
|
||||||
|
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
|
||||||
|
println!("{}", hint);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("unknown command: {}", input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => println!("error reading command: {}", error),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||||
/* Clears the terminal with an ANSI escape code.
|
/* Clears the terminal with an ANSI escape code.
|
||||||
Works in UNIX and newer Windows terminals. */
|
Works in UNIX and newer Windows terminals. */
|
||||||
|
@ -121,8 +144,11 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||||
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
|
watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;
|
||||||
|
|
||||||
clear_screen();
|
clear_screen();
|
||||||
let _ignored = verify(exercises.iter());
|
let verify_result = verify(exercises.iter());
|
||||||
|
|
||||||
|
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
|
||||||
|
let failed_exercise_hint = Arc::new(Mutex::new(verify_result.map_err(to_owned_hint).err()));
|
||||||
|
spawn_watch_shell(&failed_exercise_hint);
|
||||||
loop {
|
loop {
|
||||||
match rx.recv() {
|
match rx.recv() {
|
||||||
Ok(event) => match event {
|
Ok(event) => match event {
|
||||||
|
@ -133,7 +159,9 @@ fn watch(exercises: &[Exercise]) -> notify::Result<()> {
|
||||||
.iter()
|
.iter()
|
||||||
.skip_while(|e| !filepath.ends_with(&e.path));
|
.skip_while(|e| !filepath.ends_with(&e.path));
|
||||||
clear_screen();
|
clear_screen();
|
||||||
let _ignored = verify(pending_exercises);
|
let verify_result = verify(pending_exercises);
|
||||||
|
let mut failed_exercise_hint = failed_exercise_hint.lock().unwrap();
|
||||||
|
*failed_exercise_hint = verify_result.map_err(to_owned_hint).err();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -2,14 +2,14 @@ use crate::exercise::{Exercise, Mode, State};
|
||||||
use console::{style, Emoji};
|
use console::{style, Emoji};
|
||||||
use indicatif::ProgressBar;
|
use indicatif::ProgressBar;
|
||||||
|
|
||||||
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), ()> {
|
pub fn verify<'a>(start_at: impl IntoIterator<Item = &'a Exercise>) -> Result<(), &'a Exercise> {
|
||||||
for exercise in start_at {
|
for exercise in start_at {
|
||||||
let is_done = match exercise.mode {
|
let compile_result = match exercise.mode {
|
||||||
Mode::Test => compile_and_test_interactively(&exercise)?,
|
Mode::Test => compile_and_test_interactively(&exercise),
|
||||||
Mode::Compile => compile_only(&exercise)?,
|
Mode::Compile => compile_only(&exercise),
|
||||||
};
|
};
|
||||||
if !is_done {
|
if !compile_result.unwrap_or(false) {
|
||||||
return Err(());
|
return Err(exercise);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in New Issue