diff options
Diffstat (limited to 'crates/termsize/src/nix.rs')
-rw-r--r-- | crates/termsize/src/nix.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/crates/termsize/src/nix.rs b/crates/termsize/src/nix.rs new file mode 100644 index 0000000..77fa574 --- /dev/null +++ b/crates/termsize/src/nix.rs @@ -0,0 +1,103 @@ +// yt - A fully featured command line YouTube client +// +// Copyright (C) 2025 softprops <d.tangren@gmail.com> +// SPDX-License-Identifier: MIT +// +// This file is part of Yt. +// +// You should have received a copy of the License along with this program. +// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>. + +extern crate libc; + +use std::io::IsTerminal; + +use self::{ + super::Size, + libc::{c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ}, +}; + +/// A representation of the size of the current terminal +#[repr(C)] +#[derive(Debug)] +pub struct UnixSize { + /// number of rows + pub rows: c_ushort, + /// number of columns + pub cols: c_ushort, + x: c_ushort, + y: c_ushort, +} + +/// Gets the current terminal size +pub fn get() -> Option<Size> { + // http://rosettacode.org/wiki/Terminal_control/Dimensions#Library:_BSD_libc + if !std::io::stdout().is_terminal() { + return None; + } + let mut us = UnixSize { + rows: 0, + cols: 0, + x: 0, + y: 0, + }; + let r = unsafe { ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut us) }; + if r == 0 { + Some(Size { + rows: us.rows, + cols: us.cols, + }) + } else { + None + } +} + +#[cfg(test)] +mod tests { + use super::{super::Size, get}; + use std::process::{Command, Output, Stdio}; + + #[cfg(target_os = "macos")] + fn stty_size() -> Output { + Command::new("stty") + .arg("-f") + .arg("/dev/stderr") + .arg("size") + .stderr(Stdio::inherit()) + .output() + .expect("expected stty output") + } + + #[cfg(not(target_os = "macos"))] + fn stty_size() -> Output { + Command::new("stty") + .arg("-F") + .arg("/dev/stderr") + .arg("size") + .stderr(Stdio::inherit()) + .output() + .expect("expected stty output") + } + + #[test] + fn test_shell() { + let output = stty_size(); + assert!(output.status.success()); + let stdout = String::from_utf8(output.stdout).expect("expected utf8"); + let mut data = stdout.split_whitespace(); + let rs = data + .next() + .expect("expected row") + .parse::<u16>() + .expect("expected u16 col"); + let cs = data + .next() + .expect("expected col") + .parse::<u16>() + .expect("expected u16 col"); + if let Some(Size { rows, cols }) = get() { + assert_eq!(rows, rs); + assert_eq!(cols, cs); + } + } +} |