flatland3 0.2.0

Flatland3 terminal play client and account CLI
use std::io::stdout;
use std::panic;
use std::sync::Once;

use crossterm::event::PopKeyboardEnhancementFlags;
use crossterm::terminal::{
    disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use crossterm::ExecutableCommand;

static PANIC_HOOK: Once = Once::new();

/// Restore terminal even on panic (best-effort).
fn install_panic_hook() {
    PANIC_HOOK.call_once(|| {
        let default = panic::take_hook();
        panic::set_hook(Box::new(move |info| {
            let _ = restore_terminal();
            default(info);
        }));
    });
}

/// Enter raw mode + alternate screen. Does not enable kitty keyboard enhancements
/// (those leak escape sequences like `1;1:3u` on many terminals including Cursor).
pub fn enter() -> anyhow::Result<()> {
    install_panic_hook();
    enable_raw_mode()?;
    let mut out = stdout();
    out.execute(EnterAlternateScreen)?;
    Ok(())
}

/// Always call on exit; safe to call multiple times.
pub fn restore_terminal() -> anyhow::Result<()> {
    let mut out = stdout();
    // Pop in case an older build enabled enhancements.
    let _ = out.execute(PopKeyboardEnhancementFlags);
    let _ = disable_raw_mode();
    let _ = out.execute(LeaveAlternateScreen);
    Ok(())
}

/// Restores the terminal when dropped.
pub struct Guard;

impl Drop for Guard {
    fn drop(&mut self) {
        let _ = restore_terminal();
    }
}