lb 0.6.0

A TUI library with ASCII/Unicode graphics.
Documentation
use std::io;

use crate::mat;

pub mod key;
pub use key::{Key, Keys, ReadKeys};

pub struct Raw {
    fd: libc::c_int,
    backup: libc::termios,
}

impl Raw {
    #[inline]
    fn new() -> io::Result<Self> {
        let fd = libc::STDOUT_FILENO;

        let mut termios = c::getattr(fd)?;
        let backup = termios;

        c::makeraw(&mut termios);

        c::setattr(fd, &termios)?;

        Ok(Raw { fd, backup })
    }
}

impl Drop for Raw {
    #[inline]
    fn drop(&mut self) {
        _ = c::setattr(self.fd, &self.backup);
    }
}

#[inline]
pub fn uncook() -> io::Result<Raw> {
    Raw::new()
}

#[inline]
pub fn size() -> io::Result<mat::Size> {
    let winsize = c::winsize()?;
    Ok((winsize.ws_col as usize, winsize.ws_row as usize).into())
}

#[inline]
pub fn size_in_pixels() -> io::Result<mat::Size> {
    let winsize = c::winsize()?;
    Ok((winsize.ws_xpixel as usize, winsize.ws_ypixel as usize).into())
}

#[inline]
pub fn glyph_aspect_ratio() -> io::Result<f32> {
    let size = size()?;
    let size_px = size_in_pixels()?;

    Ok((size.height as f32 / size.width as f32) * (size_px.width as f32 / size_px.height as f32))
}

mod c {
    use std::io;
    use std::mem;

    #[inline]
    pub fn getattr(fd: libc::c_int) -> io::Result<libc::termios> {
        unsafe {
            let mut termios = mem::zeroed();
            libc::tcgetattr(fd, &mut termios).to_result()?;
            Ok(termios)
        }
    }

    #[inline]
    pub fn setattr(fd: libc::c_int, termios: &libc::termios) -> io::Result<()> {
        unsafe {
            libc::tcsetattr(fd, libc::TCSANOW, termios).to_result()?;
            Ok(())
        }
    }

    #[inline]
    pub fn makeraw(termios: &mut libc::termios) {
        unsafe {
            libc::cfmakeraw(termios);
        }

        termios.c_cc[libc::VMIN] = 0;
        termios.c_cc[libc::VTIME] = 0;
    }

    #[inline]
    pub fn winsize() -> io::Result<libc::winsize> {
        unsafe {
            let mut winsize: libc::winsize = mem::zeroed();
            libc::ioctl(libc::STDOUT_FILENO, libc::TIOCGWINSZ, &mut winsize).to_result()?;
            Ok(winsize)
        }
    }

    trait ToResult: Sized {
        fn to_result(self) -> io::Result<Self>;
    }

    impl ToResult for libc::c_int {
        #[inline]
        fn to_result(self) -> io::Result<Self> {
            if self < 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(self)
            }
        }
    }
}