Skip to content

Commit b13bafa

Browse files
authored
Merge pull request #1911 from mo8it/watch
Improvements to watch mode
2 parents b8a5886 + f995b4c commit b13bafa

File tree

3 files changed

+58
-37
lines changed

3 files changed

+58
-37
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ notify-debouncer-mini = "0.4.1"
1717
regex = "1.10.3"
1818
serde_json = "1.0.114"
1919
serde = { version = "1.0.197", features = ["derive"] }
20+
shlex = "1.3.0"
2021
toml_edit = { version = "0.22.9", default-features = false, features = ["parse", "serde"] }
2122
which = "6.0.1"
2223

src/main.rs

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use clap::{Parser, Subcommand};
66
use console::Emoji;
77
use notify_debouncer_mini::notify::{self, RecursiveMode};
88
use notify_debouncer_mini::{new_debouncer, DebouncedEventKind};
9+
use shlex::Shlex;
910
use std::ffi::OsStr;
1011
use std::fs;
1112
use std::io::{self, prelude::*};
@@ -244,47 +245,49 @@ fn main() {
244245
}
245246

246247
fn spawn_watch_shell(
247-
failed_exercise_hint: &Arc<Mutex<Option<String>>>,
248+
failed_exercise_hint: Arc<Mutex<Option<String>>>,
248249
should_quit: Arc<AtomicBool>,
249250
) {
250-
let failed_exercise_hint = Arc::clone(failed_exercise_hint);
251251
println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here.");
252-
thread::spawn(move || loop {
253-
let mut input = String::new();
254-
match io::stdin().read_line(&mut input) {
255-
Ok(_) => {
256-
let input = input.trim();
257-
if input == "hint" {
258-
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
259-
println!("{hint}");
260-
}
261-
} else if input == "clear" {
262-
println!("\x1B[2J\x1B[1;1H");
263-
} else if input.eq("quit") {
264-
should_quit.store(true, Ordering::SeqCst);
265-
println!("Bye!");
266-
} else if input.eq("help") {
267-
println!("Commands available to you in watch mode:");
268-
println!(" hint - prints the current exercise's hint");
269-
println!(" clear - clears the screen");
270-
println!(" quit - quits watch mode");
271-
println!(" !<cmd> - executes a command, like `!rustc --explain E0381`");
272-
println!(" help - displays this help message");
273-
println!();
274-
println!("Watch mode automatically re-evaluates the current exercise");
275-
println!("when you edit a file's contents.")
276-
} else if let Some(cmd) = input.strip_prefix('!') {
277-
let parts: Vec<&str> = cmd.split_whitespace().collect();
278-
if parts.is_empty() {
279-
println!("no command provided");
280-
} else if let Err(e) = Command::new(parts[0]).args(&parts[1..]).status() {
281-
println!("failed to execute command `{cmd}`: {e}");
282-
}
283-
} else {
284-
println!("unknown command: {input}");
252+
253+
thread::spawn(move || {
254+
let mut input = String::with_capacity(32);
255+
let mut stdin = io::stdin().lock();
256+
257+
loop {
258+
// Recycle input buffer.
259+
input.clear();
260+
261+
if let Err(e) = stdin.read_line(&mut input) {
262+
println!("error reading command: {e}");
263+
}
264+
265+
let input = input.trim();
266+
if input == "hint" {
267+
if let Some(hint) = &*failed_exercise_hint.lock().unwrap() {
268+
println!("{hint}");
269+
}
270+
} else if input == "clear" {
271+
println!("\x1B[2J\x1B[1;1H");
272+
} else if input == "quit" {
273+
should_quit.store(true, Ordering::SeqCst);
274+
println!("Bye!");
275+
} else if input == "help" {
276+
println!("{WATCH_MODE_HELP_MESSAGE}");
277+
} else if let Some(cmd) = input.strip_prefix('!') {
278+
let mut parts = Shlex::new(cmd);
279+
280+
let Some(program) = parts.next() else {
281+
println!("no command provided");
282+
continue;
283+
};
284+
285+
if let Err(e) = Command::new(program).args(parts).status() {
286+
println!("failed to execute command `{cmd}`: {e}");
285287
}
288+
} else {
289+
println!("unknown command: {input}\n{WATCH_MODE_HELP_MESSAGE}");
286290
}
287-
Err(error) => println!("error reading command: {error}"),
288291
}
289292
});
290293
}
@@ -345,7 +348,7 @@ fn watch(
345348
Ok(_) => return Ok(WatchStatus::Finished),
346349
Err(exercise) => Arc::new(Mutex::new(Some(exercise.hint.clone()))),
347350
};
348-
spawn_watch_shell(&failed_exercise_hint, Arc::clone(&should_quit));
351+
spawn_watch_shell(Arc::clone(&failed_exercise_hint), Arc::clone(&should_quit));
349352
loop {
350353
match rx.recv_timeout(Duration::from_secs(1)) {
351354
Ok(event) => match event {
@@ -462,3 +465,13 @@ const WELCOME: &str = r" welcome to...
462465
| | | |_| \__ \ |_| | | | | | (_| \__ \
463466
|_| \__,_|___/\__|_|_|_| |_|\__, |___/
464467
|___/";
468+
469+
const WATCH_MODE_HELP_MESSAGE: &str = "Commands available to you in watch mode:
470+
hint - prints the current exercise's hint
471+
clear - clears the screen
472+
quit - quits watch mode
473+
!<cmd> - executes a command, like `!rustc --explain E0381`
474+
help - displays this help message
475+
476+
Watch mode automatically re-evaluates the current exercise
477+
when you edit a file's contents.";

0 commit comments

Comments
 (0)