ratatui_ffi 0.2.6

C ABI bindings for Ratatui (Rust TUI) to consume from C/C#/etc.
Documentation
use crate::*;
use crossterm::{
    execute,
    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use std::io::stdout;

#[no_mangle]
pub extern "C" fn ratatui_init_terminal() -> *mut FfiTerminal {
    crate::guard_ptr("ratatui_init_terminal", || {
        let mut out = stdout();
        let want_raw = std::env::var("RATATUI_FFI_NO_RAW").is_err();
        let use_alt = std::env::var("RATATUI_FFI_ALTSCR").is_ok();
        let mut entered_alt = false;
        let mut raw_mode = false;
        if want_raw {
            if enable_raw_mode().is_ok() {
                raw_mode = true;
            }
        }
        if use_alt {
            if execute!(out, EnterAlternateScreen).is_ok() {
                entered_alt = true;
            }
        }
        let backend = CrosstermBackend::new(out);
        match Terminal::new(backend) {
            Ok(mut terminal) => {
                let _ = terminal.hide_cursor();
                let _ = terminal.clear();
                Box::into_raw(Box::new(FfiTerminal {
                    terminal,
                    entered_alt,
                    raw_mode,
                }))
            }
            Err(_) => {
                if raw_mode {
                    let _ = disable_raw_mode();
                }
                std::ptr::null_mut()
            }
        }
    })
}

#[no_mangle]
pub extern "C" fn ratatui_terminal_clear(term: *mut FfiTerminal) {
    crate::guard_void("ratatui_terminal_clear", || {
        if term.is_null() {
            return;
        }
        let t = unsafe { &mut *term };
        let _ = t.terminal.clear();
    })
}

#[no_mangle]
pub extern "C" fn ratatui_terminal_free(term: *mut FfiTerminal) {
    crate::guard_void("ratatui_terminal_free", || {
        if term.is_null() {
            return;
        }
        let mut boxed = unsafe { Box::from_raw(term) };
        let _ = boxed.terminal.show_cursor();
        if boxed.entered_alt {
            let _ = execute!(stdout(), LeaveAlternateScreen);
        }
        if boxed.raw_mode {
            let _ = disable_raw_mode();
        }
    })
}