Right now, if you press Ctrl + C, the code will exit the loop
that listens to Ctrl + C—but the process will only exit after the command has finished executing.
use std::{
io::Write,
process::{Command, Stdio},
sync::{Arc, Mutex},
thread,
time::Duration,
};
use termion::{event::Key, input::TermRead, raw::IntoRawMode};
pub struct CmdRunner {}
impl CmdRunner {
pub fn run<W: Write + Send + 'static>(&mut self, stdout_mutex: Arc<Mutex<Option<W>>>) {
let mut command = Command::new("script");
command.arg("-qec").arg("sleep 6").arg("/dev/null");
command.stdout(Stdio::piped());
command.stderr(Stdio::piped());
let mut child = command.spawn().expect("failed to spawn command");
let should_exit = Arc::new(Mutex::new(false));
let should_exit_clone = Arc::clone(&should_exit);
let mut stdin = termion::async_stdin().keys();
let handle = std::thread::spawn(move || {
loop {
if *should_exit_clone.lock().unwrap() {
println!("Exited!");
break;
}
let input = stdin.next();
if let Some(Ok(key)) = input {
match key {
Key::Ctrl('c') => {
*should_exit_clone.lock().unwrap() = true;
}
_ => {}
}
}
thread::sleep(Duration::from_millis(50));
}
});
child.wait().expect("failed to wait for command");
println!("The command finished executing!");
*should_exit.lock().unwrap() = true;
handle.join().unwrap();
}
}
fn main() {
let stdout = std::io::stdout().into_raw_mode().unwrap();
let mut command = CmdRunner {};
let stdout_mutex = Arc::new(Mutex::new(Some(stdout)));
command.run(stdout_mutex);
}
It's because of this line: child.wait().expect("failed to wait for command")
But I can't remove it, because the code has to wait for the command to finish if Ctrl + C isn't pressed.
How can I stop the command and exit the process gracefully when Ctrl + C is pressed?
Note: I removed the code that uses Arc<Mutex<W>>>
to simplify the code.