sim-cli 0.7.0

CLI tool for running and comparing Solana simulator backtests
Documentation
use std::io::{IsTerminal, stderr};

use tokio::signal::{
    ctrl_c,
    unix::{SignalKind, signal},
};
use tokio_util::sync::CancellationToken;
use tracing::{info, warn};

/// Exit code for an interrupted run (128 + SIGINT).
const EXIT_INTERRUPTED: i32 = 130;

/// First signal cancels the token (triggering a graceful session close); a
/// second signal exits immediately without waiting for it.
pub fn spawn_os_signal_handler(cancellation_token: CancellationToken) {
    tokio::spawn(async move {
        let mut terminate =
            signal(SignalKind::terminate()).expect("Failed to set up SIGTERM handler");
        let mut quit = signal(SignalKind::quit()).expect("Failed to set up SIGQUIT handler");

        tokio::select! {
            _ = ctrl_c() => info!("Received Ctrl+C"),
            _ = terminate.recv() => info!("Received SIGTERM"),
            _ = quit.recv() => info!("Received SIGQUIT"),
            _ = cancellation_token.cancelled() => return,
        }
        cancellation_token.cancel();

        tokio::select! {
            _ = ctrl_c() => {}
            _ = terminate.recv() => {}
            _ = quit.recv() => {}
        }
        warn!("Received second signal; exiting without graceful close");
        std::process::exit(EXIT_INTERRUPTED);
    });
}

/// Spawn a task that erases the "^C" terminal echo on Ctrl+C.
///
/// When Ctrl+C is pressed, the terminal echoes "^C" on the current line, which shifts
/// indicatif's cursor tracking by one line and causes the top progress bar to be rendered twice.
/// This moves the cursor back up so that it's in the right position before re-rendering.
pub fn spawn_ctrlc_cursor_fix() {
    if stderr().is_terminal() {
        tokio::spawn(async {
            if ctrl_c().await.is_ok() {
                eprint!("\r\x1b[2K\x1b[1A");
            }
        });
    }
}