use std::sync::LazyLock as Lazy;
use std::sync::atomic::{AtomicBool, Ordering};
use console::Term;
use tokio::sync::Notify;
use windows_sys::Win32::Foundation::{FALSE, TRUE};
use windows_sys::Win32::System::Console::{CTRL_BREAK_EVENT, CTRL_C_EVENT, SetConsoleCtrlHandler};
use windows_sys::core::BOOL;
use mise_util::cmd::CmdLineRunner;
static EXIT: AtomicBool = AtomicBool::new(true);
static SHOW_CURSOR: AtomicBool = AtomicBool::new(false);
static SHOULD_EXIT: AtomicBool = AtomicBool::new(false);
static INSTALLED: AtomicBool = AtomicBool::new(false);
static INTERRUPTED: Lazy<Notify> = Lazy::new(Notify::new);
unsafe extern "system" fn handler(ctrl_type: u32) -> BOOL {
match ctrl_type {
CTRL_C_EVENT | CTRL_BREAK_EVENT => {
if EXIT.load(Ordering::Relaxed) || mise_util::cancel::mark() {
SHOULD_EXIT.store(true, Ordering::Relaxed);
}
INTERRUPTED.notify_one();
TRUE
}
_ => FALSE,
}
}
fn install_handler() {
if INSTALLED.swap(true, Ordering::Relaxed) {
return;
}
Lazy::force(&INTERRUPTED);
if unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } == FALSE {
log::debug!(
"failed to install console ctrl handler: {}",
std::io::Error::last_os_error()
);
}
}
const INTERRUPTED_EXIT_CODE: i32 = 130;
pub async fn exit_signal() -> i32 {
if crate::in_tests() {
return std::future::pending().await;
}
loop {
INTERRUPTED.notified().await;
if SHOW_CURSOR.load(Ordering::Relaxed) {
let _ = Term::stderr().show_cursor();
}
crate::run_interrupt_hook();
if SHOULD_EXIT.load(Ordering::Relaxed) {
log::debug!("Ctrl-C pressed, exiting...");
CmdLineRunner::kill_all();
return INTERRUPTED_EXIT_CODE;
}
log::info!(
"interrupted, waiting for running commands to exit (press Ctrl-C again to stop them)"
);
}
}
pub fn exit_on_ctrl_c(do_exit: bool) {
if crate::in_tests() {
return;
}
EXIT.store(do_exit, Ordering::Relaxed);
mise_util::cancel::reset();
install_handler();
}
pub fn is_cancelled() -> bool {
if crate::in_tests() {
return false;
}
mise_util::cancel::is_cancelled()
}
pub fn show_cursor_after_ctrl_c() {
if crate::in_tests() {
return;
}
SHOW_CURSOR.store(true, Ordering::Relaxed);
}