use nix::sys::termios::{tcgetattr, tcsetattr, SetArg, Termios};
use serde::{Deserialize, Serialize};
use std::os::unix::io::{BorrowedFd, RawFd};
use crate::error::{NdsError, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TerminalState {
pub window_size: (u16, u16), pub cursor_position: Option<(u16, u16)>, #[serde(skip)]
pub termios: Option<Termios>,
}
impl TerminalState {
pub fn capture(fd: RawFd) -> Result<Self> {
let (cols, rows) = Self::get_window_size(fd)?;
let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
let termios = tcgetattr(&borrowed_fd).ok();
Ok(TerminalState {
window_size: (cols, rows),
cursor_position: None, termios,
})
}
pub fn restore(&self, fd: RawFd) -> Result<()> {
Self::set_window_size(fd, self.window_size.0, self.window_size.1)?;
if let Some(ref termios) = self.termios {
let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
tcsetattr(&borrowed_fd, SetArg::TCSANOW, termios).map_err(|e| {
NdsError::TerminalError(format!("Failed to restore termios: {}", e))
})?;
}
Ok(())
}
fn get_window_size(fd: RawFd) -> Result<(u16, u16)> {
unsafe {
let mut winsize = libc::winsize {
ws_row: 0,
ws_col: 0,
ws_xpixel: 0,
ws_ypixel: 0,
};
if libc::ioctl(fd, libc::TIOCGWINSZ as u64, &mut winsize) < 0 {
return Err(NdsError::TerminalError(
"Failed to get window size".to_string(),
));
}
Ok((winsize.ws_col, winsize.ws_row))
}
}
fn set_window_size(fd: RawFd, cols: u16, rows: u16) -> Result<()> {
unsafe {
let winsize = libc::winsize {
ws_row: rows,
ws_col: cols,
ws_xpixel: 0,
ws_ypixel: 0,
};
if libc::ioctl(fd, libc::TIOCSWINSZ as u64, &winsize) < 0 {
return Err(NdsError::TerminalError(
"Failed to set window size".to_string(),
));
}
Ok(())
}
}
}
pub struct TerminalCommands;
impl TerminalCommands {
pub fn refresh_display() -> &'static [u8] {
b"\x0c"
}
pub fn redraw_prompt() -> &'static [u8] {
b"\n\x1b[A" }
}