mirror of https://github.com/rust-lang/rustlings
Start with the TUI
parent
0bf51c6a0d
commit
b0f19fd862
@ -0,0 +1,59 @@
|
||||
pub const WELCOME: &str = r" welcome to...
|
||||
_ _ _
|
||||
_ __ _ _ ___| |_| (_)_ __ __ _ ___
|
||||
| '__| | | / __| __| | | '_ \ / _` / __|
|
||||
| | | |_| \__ \ |_| | | | | | (_| \__ \
|
||||
|_| \__,_|___/\__|_|_|_| |_|\__, |___/
|
||||
|___/";
|
||||
|
||||
pub const DEFAULT_OUT: &str =
|
||||
"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
|
||||
started, here's a couple of notes about how Rustlings operates:
|
||||
|
||||
1. The central concept behind Rustlings is that you solve exercises. These
|
||||
exercises usually have some sort of syntax error in them, which will cause
|
||||
them to fail compilation or testing. Sometimes there's a logic error instead
|
||||
of a syntax error. No matter what error, it's your job to find it and fix it!
|
||||
You'll know when you fixed it because then, the exercise will compile and
|
||||
Rustlings will be able to move on to the next exercise.
|
||||
2. If you run Rustlings in watch mode (which we recommend), it'll automatically
|
||||
start with the first exercise. Don't get confused by an error message popping
|
||||
up as soon as you run Rustlings! This is part of the exercise that you're
|
||||
supposed to solve, so open the exercise file in an editor and start your
|
||||
detective work!
|
||||
3. If you're stuck on an exercise, there is a helpful hint you can view by typing
|
||||
'hint' (in watch mode), or running `rustlings hint exercise_name`.
|
||||
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
|
||||
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
|
||||
and sometimes, other learners do too so you can help each other out!
|
||||
|
||||
Got all that? Great! To get started, run `rustlings watch` in order to get the first exercise.
|
||||
Make sure to have your editor open in the `rustlings` directory!";
|
||||
|
||||
pub const FENISH_LINE: &str = "+----------------------------------------------------+
|
||||
| You made it to the Fe-nish line! |
|
||||
+-------------------------- ------------------------+
|
||||
\\/\x1b[31m
|
||||
▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒
|
||||
▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒
|
||||
▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒
|
||||
░░▒▒▒▒░░▒▒ ▒▒ ▒▒ ▒▒ ▒▒░░▒▒▒▒
|
||||
▓▓▓▓▓▓▓▓ ▓▓ ▓▓██ ▓▓ ▓▓██ ▓▓ ▓▓▓▓▓▓▓▓
|
||||
▒▒▒▒ ▒▒ ████ ▒▒ ████ ▒▒░░ ▒▒▒▒
|
||||
▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒
|
||||
▒▒▒▒▒▒▒▒▒▒▓▓▓▓▓▓▒▒▒▒▒▒▒▒▓▓▒▒▓▓▒▒▒▒▒▒▒▒
|
||||
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
|
||||
▒▒▒▒▒▒▒▒▒▒██▒▒▒▒▒▒██▒▒▒▒▒▒▒▒▒▒
|
||||
▒▒ ▒▒▒▒▒▒▒▒▒▒██████▒▒▒▒▒▒▒▒▒▒ ▒▒
|
||||
▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒
|
||||
▒▒ ▒▒ ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ▒▒ ▒▒
|
||||
▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒
|
||||
▒▒ ▒▒ ▒▒ ▒▒\x1b[0m
|
||||
|
||||
We hope you enjoyed learning about the various aspects of Rust!
|
||||
If you noticed any issues, please don't hesitate to report them to our repo.
|
||||
You can also contribute your own exercises to help the greater community!
|
||||
|
||||
Before reporting an issue or contributing, please read our guidelines:
|
||||
https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md";
|
@ -0,0 +1,92 @@
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
ExecutableCommand,
|
||||
};
|
||||
use notify_debouncer_mini::{new_debouncer, notify::RecursiveMode, DebouncedEventKind};
|
||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||
use std::{
|
||||
io::stdout,
|
||||
path::Path,
|
||||
sync::mpsc::{channel, RecvTimeoutError},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
exercise::Exercise,
|
||||
verify::{verify, VerifyState},
|
||||
};
|
||||
|
||||
fn watch(exercises: &[Exercise]) -> Result<()> {
|
||||
let (tx, rx) = channel();
|
||||
|
||||
let mut debouncer = new_debouncer(Duration::from_secs(1), tx)?;
|
||||
debouncer
|
||||
.watcher()
|
||||
.watch(Path::new("exercises"), RecursiveMode::Recursive)?;
|
||||
|
||||
let mut failed_exercise_hint = match verify(exercises, (0, exercises.len()))? {
|
||||
VerifyState::AllExercisesDone => return Ok(()),
|
||||
VerifyState::Failed(exercise) => Some(&exercise.hint),
|
||||
};
|
||||
|
||||
let mut pending_exercises = Vec::with_capacity(exercises.len());
|
||||
loop {
|
||||
match rx.recv_timeout(Duration::from_secs(1)) {
|
||||
Ok(event) => match event {
|
||||
Ok(events) => {
|
||||
for event in events {
|
||||
if event.kind == DebouncedEventKind::Any
|
||||
&& event.path.extension().is_some_and(|ext| ext == "rs")
|
||||
{
|
||||
pending_exercises.extend(exercises.iter().filter(|exercise| {
|
||||
!exercise.looks_done().unwrap_or(false)
|
||||
|| event.path.ends_with(&exercise.path)
|
||||
}));
|
||||
let num_done = exercises.len() - pending_exercises.len();
|
||||
|
||||
match verify(
|
||||
pending_exercises.iter().copied(),
|
||||
(num_done, exercises.len()),
|
||||
)? {
|
||||
VerifyState::AllExercisesDone => return Ok(()),
|
||||
VerifyState::Failed(exercise) => {
|
||||
failed_exercise_hint = Some(&exercise.hint);
|
||||
}
|
||||
}
|
||||
|
||||
pending_exercises.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => println!("watch error: {e:?}"),
|
||||
},
|
||||
Err(RecvTimeoutError::Timeout) => {
|
||||
// the timeout expired, just check the `should_quit` variable below then loop again
|
||||
}
|
||||
Err(e) => println!("watch error: {e:?}"),
|
||||
}
|
||||
|
||||
// TODO: Check if we need to exit
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tui(exercises: &[Exercise]) -> Result<()> {
|
||||
let mut stdout = stdout().lock();
|
||||
stdout.execute(EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(&mut stdout))?;
|
||||
terminal.clear()?;
|
||||
|
||||
watch(exercises)?;
|
||||
|
||||
drop(terminal);
|
||||
stdout.execute(LeaveAlternateScreen)?;
|
||||
disable_raw_mode()?;
|
||||
|
||||
// TODO
|
||||
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");
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue