use crate::Session; use libc::c_int; use nix::sys::signal::*; use std::sync::*; static SESSION: Mutex>>> = Mutex::new(None); fn handle() { let Ok(mut se) = SESSION.lock() else { return }; let Some(se) = se.as_mut() else { return }; let Ok(mut se) = se.lock() else { return }; se.ctrlc.pressed = true; } extern "C" fn c_handle(_signal: c_int) { // cannot propagate panic into C-land let _ = std::panic::catch_unwind(|| { if let Err(e) = std::panic::catch_unwind(handle) { eprintln!("{e:?}"); // might panic } }); } #[derive(Default)] pub struct CtrlC { pressed: bool, } struct Teardown; impl Drop for Teardown { fn drop(&mut self) { teardown(); } } fn teardown() { unsafe { let _ = signal(Signal::SIGINT, SigHandler::SigDfl); } if let Ok(mut se) = SESSION.lock() { *se = None; } } #[must_use] pub fn setup(session: Arc>) -> impl Drop { *SESSION.lock().unwrap() = Some(session); unsafe { signal(Signal::SIGINT, SigHandler::Handler(c_handle)) .expect("failed to set ctrl+c signal handler"); } Teardown } pub fn peek(session: &Session) -> bool { session.ctrlc.pressed } pub fn pop(session: &mut Session) -> bool { let x = session.ctrlc.pressed; session.ctrlc.pressed = false; x }