mirror of
https://github.com/rust-lang/rustlings.git
synced 2024-12-26 15:26:29 +00:00
Merge branch 'main' into which
This commit is contained in:
commit
8e0f7e56f7
6 changed files with 29 additions and 44 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -271,15 +271,6 @@ version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "home"
|
|
||||||
version = "0.5.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.52.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.5"
|
version = "2.2.5"
|
||||||
|
@ -564,7 +555,6 @@ dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"console",
|
"console",
|
||||||
"glob",
|
"glob",
|
||||||
"home",
|
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"notify-debouncer-mini",
|
"notify-debouncer-mini",
|
||||||
"predicates",
|
"predicates",
|
||||||
|
|
|
@ -12,7 +12,6 @@ edition = "2021"
|
||||||
clap = { version = "4.5.2", features = ["derive"] }
|
clap = { version = "4.5.2", features = ["derive"] }
|
||||||
console = "0.15.8"
|
console = "0.15.8"
|
||||||
glob = "0.3.0"
|
glob = "0.3.0"
|
||||||
home = "0.5.9"
|
|
||||||
indicatif = "0.17.8"
|
indicatif = "0.17.8"
|
||||||
notify-debouncer-mini = "0.4.1"
|
notify-debouncer-mini = "0.4.1"
|
||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
|
|
|
@ -58,7 +58,7 @@ pub struct Exercise {
|
||||||
|
|
||||||
// An enum to track of the state of an Exercise.
|
// An enum to track of the state of an Exercise.
|
||||||
// An Exercise can be either Done or Pending
|
// An Exercise can be either Done or Pending
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub enum State {
|
pub enum State {
|
||||||
// The state of the exercise once it's been completed
|
// The state of the exercise once it's been completed
|
||||||
Done,
|
Done,
|
||||||
|
@ -67,7 +67,7 @@ pub enum State {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The context information of a pending exercise
|
// The context information of a pending exercise
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
pub struct ContextLine {
|
pub struct ContextLine {
|
||||||
// The source code that is still pending completion
|
// The source code that is still pending completion
|
||||||
pub line: String,
|
pub line: String,
|
||||||
|
|
20
src/main.rs
20
src/main.rs
|
@ -217,16 +217,13 @@ fn main() {
|
||||||
println!("Failed to write rust-project.json to disk for rust-analyzer");
|
println!("Failed to write rust-project.json to disk for rust-analyzer");
|
||||||
} else {
|
} else {
|
||||||
println!("Successfully generated rust-project.json");
|
println!("Successfully generated rust-project.json");
|
||||||
println!("rust-analyzer will now parse exercises, restart your language server or editor")
|
println!("rust-analyzer will now parse exercises, restart your language server or editor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Subcommands::Watch { success_hints } => match watch(&exercises, verbose, success_hints) {
|
Subcommands::Watch { success_hints } => match watch(&exercises, verbose, success_hints) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!(
|
println!("Error: Could not watch your progress. Error message was {e:?}.");
|
||||||
"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);
|
||||||
}
|
}
|
||||||
|
@ -280,7 +277,7 @@ fn spawn_watch_shell(
|
||||||
if parts.is_empty() {
|
if parts.is_empty() {
|
||||||
println!("no command provided");
|
println!("no command provided");
|
||||||
} else if let Err(e) = Command::new(parts[0]).args(&parts[1..]).status() {
|
} else if let Err(e) = Command::new(parts[0]).args(&parts[1..]).status() {
|
||||||
println!("failed to execute command `{}`: {}", cmd, e);
|
println!("failed to execute command `{cmd}`: {e}");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
println!("unknown command: {input}");
|
println!("unknown command: {input}");
|
||||||
|
@ -292,7 +289,7 @@ fn spawn_watch_shell(
|
||||||
}
|
}
|
||||||
|
|
||||||
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 == "next" {
|
||||||
exercises
|
exercises
|
||||||
.iter()
|
.iter()
|
||||||
.find(|e| !e.looks_done())
|
.find(|e| !e.looks_done())
|
||||||
|
@ -338,7 +335,6 @@ fn watch(
|
||||||
|
|
||||||
clear_screen();
|
clear_screen();
|
||||||
|
|
||||||
let to_owned_hint = |t: &Exercise| t.hint.to_owned();
|
|
||||||
let failed_exercise_hint = match verify(
|
let failed_exercise_hint = match verify(
|
||||||
exercises.iter(),
|
exercises.iter(),
|
||||||
(0, exercises.len()),
|
(0, exercises.len()),
|
||||||
|
@ -346,7 +342,7 @@ fn watch(
|
||||||
success_hints,
|
success_hints,
|
||||||
) {
|
) {
|
||||||
Ok(_) => return Ok(WatchStatus::Finished),
|
Ok(_) => return Ok(WatchStatus::Finished),
|
||||||
Err(exercise) => Arc::new(Mutex::new(Some(to_owned_hint(exercise)))),
|
Err(exercise) => Arc::new(Mutex::new(Some(exercise.hint.clone()))),
|
||||||
};
|
};
|
||||||
spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit));
|
spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit));
|
||||||
loop {
|
loop {
|
||||||
|
@ -383,7 +379,7 @@ fn watch(
|
||||||
Err(exercise) => {
|
Err(exercise) => {
|
||||||
let mut failed_exercise_hint =
|
let mut failed_exercise_hint =
|
||||||
failed_exercise_hint.lock().unwrap();
|
failed_exercise_hint.lock().unwrap();
|
||||||
*failed_exercise_hint = Some(to_owned_hint(exercise));
|
*failed_exercise_hint = Some(exercise.hint.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +399,7 @@ fn watch(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_OUT: &str = r#"Thanks for installing Rustlings!
|
const DEFAULT_OUT: &str = "Thanks for installing Rustlings!
|
||||||
|
|
||||||
Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
Is this your first time? Don't worry, Rustlings was made for beginners! We are
|
||||||
going to teach you a lot of things about Rust, but before we can get
|
going to teach you a lot of things about Rust, but before we can get
|
||||||
|
@ -429,7 +425,7 @@ started, here's a couple of notes about how Rustlings operates:
|
||||||
autocompletion, run the command `rustlings lsp`.
|
autocompletion, run the command `rustlings lsp`.
|
||||||
|
|
||||||
Got all that? Great! To get started, run `rustlings watch` in order to get the first
|
Got all that? Great! To get started, run `rustlings watch` in order to get the first
|
||||||
exercise. Make sure to have your editor open!"#;
|
exercise. Make sure to have your editor open!";
|
||||||
|
|
||||||
const FENISH_LINE: &str = "+----------------------------------------------------+
|
const FENISH_LINE: &str = "+----------------------------------------------------+
|
||||||
| You made it to the Fe-nish line! |
|
| You made it to the Fe-nish line! |
|
||||||
|
|
|
@ -21,7 +21,8 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> {
|
||||||
// Resets the exercise by stashing the changes.
|
// Resets the exercise by stashing the changes.
|
||||||
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
|
pub fn reset(exercise: &Exercise) -> Result<(), ()> {
|
||||||
let command = Command::new("git")
|
let command = Command::new("git")
|
||||||
.args(["stash", "--"])
|
.arg("stash")
|
||||||
|
.arg("--")
|
||||||
.arg(&exercise.path)
|
.arg(&exercise.path)
|
||||||
.spawn();
|
.spawn();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub fn verify<'a>(
|
||||||
.progress_chars("#>-"),
|
.progress_chars("#>-"),
|
||||||
);
|
);
|
||||||
bar.set_position(num_done as u64);
|
bar.set_position(num_done as u64);
|
||||||
bar.set_message(format!("({:.1} %)", percentage));
|
bar.set_message(format!("({percentage:.1} %)"));
|
||||||
|
|
||||||
for exercise in exercises {
|
for exercise in exercises {
|
||||||
let compile_result = match exercise.mode {
|
let compile_result = match exercise.mode {
|
||||||
|
@ -37,7 +37,7 @@ pub fn verify<'a>(
|
||||||
}
|
}
|
||||||
percentage += 100.0 / total as f32;
|
percentage += 100.0 / total as f32;
|
||||||
bar.inc(1);
|
bar.inc(1);
|
||||||
bar.set_message(format!("({:.1} %)", percentage));
|
bar.set_message(format!("({percentage:.1} %)"));
|
||||||
if bar.position() == total as u64 {
|
if bar.position() == total as u64 {
|
||||||
println!(
|
println!(
|
||||||
"Progress: You completed {} / {} exercises ({:.1} %).",
|
"Progress: You completed {} / {} exercises ({:.1} %).",
|
||||||
|
@ -51,6 +51,7 @@ pub fn verify<'a>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
enum RunMode {
|
enum RunMode {
|
||||||
Interactive,
|
Interactive,
|
||||||
NonInteractive,
|
NonInteractive,
|
||||||
|
@ -124,7 +125,7 @@ fn compile_and_test(
|
||||||
if verbose {
|
if verbose {
|
||||||
println!("{}", output.stdout);
|
println!("{}", output.stdout);
|
||||||
}
|
}
|
||||||
if let RunMode::Interactive = run_mode {
|
if run_mode == RunMode::Interactive {
|
||||||
Ok(prompt_for_completion(exercise, None, success_hints))
|
Ok(prompt_for_completion(exercise, None, success_hints))
|
||||||
} else {
|
} else {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
|
@ -191,27 +192,25 @@ fn prompt_for_completion(
|
||||||
Mode::Test => "The code is compiling, and the tests pass!",
|
Mode::Test => "The code is compiling, and the tests pass!",
|
||||||
Mode::Clippy => clippy_success_msg,
|
Mode::Clippy => clippy_success_msg,
|
||||||
};
|
};
|
||||||
println!();
|
|
||||||
if no_emoji {
|
if no_emoji {
|
||||||
println!("~*~ {success_msg} ~*~")
|
println!("\n~*~ {success_msg} ~*~\n");
|
||||||
} else {
|
} else {
|
||||||
println!("🎉 🎉 {success_msg} 🎉 🎉")
|
println!("\n🎉 🎉 {success_msg} 🎉 🎉\n");
|
||||||
}
|
}
|
||||||
println!();
|
|
||||||
|
|
||||||
if let Some(output) = prompt_output {
|
if let Some(output) = prompt_output {
|
||||||
println!("Output:");
|
println!(
|
||||||
println!("{}", separator());
|
"Output:\n{separator}\n{output}\n{separator}\n",
|
||||||
println!("{output}");
|
separator = separator(),
|
||||||
println!("{}", separator());
|
);
|
||||||
println!();
|
|
||||||
}
|
}
|
||||||
if success_hints {
|
if success_hints {
|
||||||
println!("Hints:");
|
println!(
|
||||||
println!("{}", separator());
|
"Hints:\n{separator}\n{}\n{separator}\n",
|
||||||
println!("{}", exercise.hint);
|
exercise.hint,
|
||||||
println!("{}", separator());
|
separator = separator(),
|
||||||
println!();
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("You can keep working on this exercise,");
|
println!("You can keep working on this exercise,");
|
||||||
|
@ -231,7 +230,7 @@ fn prompt_for_completion(
|
||||||
"{:>2} {} {}",
|
"{:>2} {} {}",
|
||||||
style(context_line.number).blue().bold(),
|
style(context_line.number).blue().bold(),
|
||||||
style("|").blue(),
|
style("|").blue(),
|
||||||
formatted_line
|
formatted_line,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue