rskit_process/pty/
size.rs1use std::os::unix::io::AsRawFd;
4
5#[derive(Debug, Clone, Copy, Eq, PartialEq)]
10pub struct PtySize {
11 pub rows: u16,
13 pub cols: u16,
15 pub pixel_width: u16,
17 pub pixel_height: u16,
19}
20
21impl Default for PtySize {
22 fn default() -> Self {
24 Self {
25 rows: 24,
26 cols: 80,
27 pixel_width: 0,
28 pixel_height: 0,
29 }
30 }
31}
32
33impl PtySize {
34 #[must_use]
36 pub const fn new(rows: u16, cols: u16) -> Self {
37 Self {
38 rows,
39 cols,
40 pixel_width: 0,
41 pixel_height: 0,
42 }
43 }
44
45 pub(crate) const fn to_winsize(self) -> libc::winsize {
47 libc::winsize {
48 ws_row: self.rows,
49 ws_col: self.cols,
50 ws_xpixel: self.pixel_width,
51 ws_ypixel: self.pixel_height,
52 }
53 }
54}
55
56#[must_use]
62pub fn terminal_size(fd: &impl AsRawFd) -> Option<PtySize> {
63 let mut winsize: libc::winsize = unsafe { std::mem::zeroed() };
66 let result = unsafe { libc::ioctl(fd.as_raw_fd(), libc::TIOCGWINSZ, &raw mut winsize) };
70 if result != 0 {
71 return None;
72 }
73 Some(PtySize {
74 rows: winsize.ws_row,
75 cols: winsize.ws_col,
76 pixel_width: winsize.ws_xpixel,
77 pixel_height: winsize.ws_ypixel,
78 })
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn default_is_eighty_by_twenty_four() {
87 let size = PtySize::default();
88 assert_eq!(size.cols, 80);
89 assert_eq!(size.rows, 24);
90 assert_eq!(size.pixel_width, 0);
91 assert_eq!(size.pixel_height, 0);
92 }
93
94 #[test]
95 fn new_sets_rows_and_cols_only() {
96 let size = PtySize::new(40, 120);
97 assert_eq!(size.rows, 40);
98 assert_eq!(size.cols, 120);
99 assert_eq!(size.pixel_width, 0);
100 }
101
102 #[test]
103 fn winsize_round_trips_dimensions() {
104 let winsize = PtySize {
105 rows: 10,
106 cols: 20,
107 pixel_width: 30,
108 pixel_height: 40,
109 }
110 .to_winsize();
111 assert_eq!(winsize.ws_row, 10);
112 assert_eq!(winsize.ws_col, 20);
113 assert_eq!(winsize.ws_xpixel, 30);
114 assert_eq!(winsize.ws_ypixel, 40);
115 }
116
117 #[test]
118 fn non_terminal_fd_has_no_size() {
119 let (reader, _writer) = std::io::pipe().expect("pipe");
121 assert!(terminal_size(&reader).is_none());
122 }
123
124 #[test]
125 fn pty_slave_reports_configured_terminal_size() {
126 let pair = crate::pty::open_pty(PtySize::new(33, 111)).expect("openpty");
127 let size = terminal_size(&pair.slave).expect("pty slave has size");
128
129 assert_eq!(size.rows, 33);
130 assert_eq!(size.cols, 111);
131 }
132}