detached_shell/
terminal_state.rs1use nix::sys::termios::{tcgetattr, tcsetattr, SetArg, Termios};
2use serde::{Deserialize, Serialize};
3use std::os::unix::io::{BorrowedFd, RawFd};
4
5use crate::error::{NdsError, Result};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct TerminalState {
10 pub window_size: (u16, u16), pub cursor_position: Option<(u16, u16)>, #[serde(skip)]
13 pub termios: Option<Termios>,
14}
15
16impl TerminalState {
17 pub fn capture(fd: RawFd) -> Result<Self> {
18 let (cols, rows) = Self::get_window_size(fd)?;
20
21 let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
23 let termios = tcgetattr(&borrowed_fd).ok();
24
25 Ok(TerminalState {
26 window_size: (cols, rows),
27 cursor_position: None, termios,
29 })
30 }
31
32 pub fn restore(&self, fd: RawFd) -> Result<()> {
33 Self::set_window_size(fd, self.window_size.0, self.window_size.1)?;
35
36 if let Some(ref termios) = self.termios {
38 let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
39 tcsetattr(&borrowed_fd, SetArg::TCSANOW, termios).map_err(|e| {
40 NdsError::TerminalError(format!("Failed to restore termios: {}", e))
41 })?;
42 }
43
44 Ok(())
45 }
46
47 fn get_window_size(fd: RawFd) -> Result<(u16, u16)> {
48 unsafe {
49 let mut winsize = libc::winsize {
50 ws_row: 0,
51 ws_col: 0,
52 ws_xpixel: 0,
53 ws_ypixel: 0,
54 };
55
56 if libc::ioctl(fd, libc::TIOCGWINSZ as u64, &mut winsize) < 0 {
57 return Err(NdsError::TerminalError(
58 "Failed to get window size".to_string(),
59 ));
60 }
61
62 Ok((winsize.ws_col, winsize.ws_row))
63 }
64 }
65
66 fn set_window_size(fd: RawFd, cols: u16, rows: u16) -> Result<()> {
67 unsafe {
68 let winsize = libc::winsize {
69 ws_row: rows,
70 ws_col: cols,
71 ws_xpixel: 0,
72 ws_ypixel: 0,
73 };
74
75 if libc::ioctl(fd, libc::TIOCSWINSZ as u64, &winsize) < 0 {
76 return Err(NdsError::TerminalError(
77 "Failed to set window size".to_string(),
78 ));
79 }
80
81 Ok(())
82 }
83 }
84}
85
86pub struct TerminalCommands;
88
89impl TerminalCommands {
90 pub fn refresh_display() -> &'static [u8] {
92 b"\x0c"
94 }
95
96 pub fn redraw_prompt() -> &'static [u8] {
98 b"\n\x1b[A" }
101}