use std::os::unix::io::AsRawFd;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct PtySize {
pub rows: u16,
pub cols: u16,
pub pixel_width: u16,
pub pixel_height: u16,
}
impl Default for PtySize {
fn default() -> Self {
Self {
rows: 24,
cols: 80,
pixel_width: 0,
pixel_height: 0,
}
}
}
impl PtySize {
#[must_use]
pub const fn new(rows: u16, cols: u16) -> Self {
Self {
rows,
cols,
pixel_width: 0,
pixel_height: 0,
}
}
pub(crate) const fn to_winsize(self) -> libc::winsize {
libc::winsize {
ws_row: self.rows,
ws_col: self.cols,
ws_xpixel: self.pixel_width,
ws_ypixel: self.pixel_height,
}
}
}
#[must_use]
pub fn terminal_size(fd: &impl AsRawFd) -> Option<PtySize> {
let mut winsize: libc::winsize = unsafe { std::mem::zeroed() };
let result = unsafe { libc::ioctl(fd.as_raw_fd(), libc::TIOCGWINSZ, &raw mut winsize) };
if result != 0 {
return None;
}
Some(PtySize {
rows: winsize.ws_row,
cols: winsize.ws_col,
pixel_width: winsize.ws_xpixel,
pixel_height: winsize.ws_ypixel,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_is_eighty_by_twenty_four() {
let size = PtySize::default();
assert_eq!(size.cols, 80);
assert_eq!(size.rows, 24);
assert_eq!(size.pixel_width, 0);
assert_eq!(size.pixel_height, 0);
}
#[test]
fn new_sets_rows_and_cols_only() {
let size = PtySize::new(40, 120);
assert_eq!(size.rows, 40);
assert_eq!(size.cols, 120);
assert_eq!(size.pixel_width, 0);
}
#[test]
fn winsize_round_trips_dimensions() {
let winsize = PtySize {
rows: 10,
cols: 20,
pixel_width: 30,
pixel_height: 40,
}
.to_winsize();
assert_eq!(winsize.ws_row, 10);
assert_eq!(winsize.ws_col, 20);
assert_eq!(winsize.ws_xpixel, 30);
assert_eq!(winsize.ws_ypixel, 40);
}
#[test]
fn non_terminal_fd_has_no_size() {
let (reader, _writer) = std::io::pipe().expect("pipe");
assert!(terminal_size(&reader).is_none());
}
#[test]
fn pty_slave_reports_configured_terminal_size() {
let pair = crate::pty::open_pty(PtySize::new(33, 111)).expect("openpty");
let size = terminal_size(&pair.slave).expect("pty slave has size");
assert_eq!(size.rows, 33);
assert_eq!(size.cols, 111);
}
}