diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-16 10:10:07 +0100 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2025-02-16 10:10:07 +0100 |
commit | 9da970f1f44f19432680e255f91f73fbb8fbe3c8 (patch) | |
tree | 7bf2e5ded6d81b4ae76a080eaa5f80418343a5a9 /crates/termsize/src | |
parent | refactor(treewide): Remove all references of the now obsolete update_raw.py (diff) | |
download | yt-9da970f1f44f19432680e255f91f73fbb8fbe3c8.zip |
chore(crates/termsize): Vendor
Diffstat (limited to '')
-rw-r--r-- | crates/termsize/src/lib.rs | 53 | ||||
-rw-r--r-- | crates/termsize/src/nix.rs | 103 | ||||
-rw-r--r-- | crates/termsize/src/other.rs | 14 | ||||
-rw-r--r-- | crates/termsize/src/win.rs | 52 |
4 files changed, 222 insertions, 0 deletions
diff --git a/crates/termsize/src/lib.rs b/crates/termsize/src/lib.rs new file mode 100644 index 0000000..e037176 --- /dev/null +++ b/crates/termsize/src/lib.rs @@ -0,0 +1,53 @@ +#![deny(missing_docs)] + +// 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>. + +//! Termsize is a tiny crate that provides a simple +//! interface for retrieving the current +//! [terminal interface](http://www.manpagez.com/man/4/tty/) size +//! +//! ```rust +//! extern crate termsize; +//! +//! termsize::get().map(|size| println!("rows {} cols {}", size.rows, size.cols)); +//! ``` + +/// Container for number of rows and columns +#[derive(Debug)] +pub struct Size { + /// number of rows + pub rows: u16, + /// number of columns + pub cols: u16, +} + +#[cfg(unix)] +#[path = "nix.rs"] +mod imp; + +#[cfg(windows)] +#[path = "win.rs"] +mod imp; + +#[cfg(not(any(unix, windows)))] +#[path = "other.rs"] +mod imp; + +pub use imp::get; + +#[cfg(test)] +mod tests { + use super::get; + #[test] + fn test_get() { + assert!(get().is_some()) + } +} 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); + } + } +} diff --git a/crates/termsize/src/other.rs b/crates/termsize/src/other.rs new file mode 100644 index 0000000..8a02f22 --- /dev/null +++ b/crates/termsize/src/other.rs @@ -0,0 +1,14 @@ +// 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>. + +/// Gets the current terminal size +pub fn get() -> Option<super::Size> { + None +} diff --git a/crates/termsize/src/win.rs b/crates/termsize/src/win.rs new file mode 100644 index 0000000..666a0fc --- /dev/null +++ b/crates/termsize/src/win.rs @@ -0,0 +1,52 @@ +// 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>. + +use std::ptr; + +use winapi::um::{ + fileapi::{CreateFileA, OPEN_EXISTING}, + handleapi::INVALID_HANDLE_VALUE, + wincon::{GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO}, + winnt::{FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}, +}; + +use self::super::Size; + +/// Gets the current terminal size +pub fn get() -> Option<Size> { + // http://rosettacode.org/wiki/Terminal_control/Dimensions#Windows + let handle = unsafe { + CreateFileA( + b"CONOUT$\0".as_ptr() as *const i8, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_WRITE, + ptr::null_mut(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ) + }; + if handle == INVALID_HANDLE_VALUE { + return None; + } + let info = unsafe { + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx + let mut info = ::std::mem::MaybeUninit::<CONSOLE_SCREEN_BUFFER_INFO>::uninit(); + if GetConsoleScreenBufferInfo(handle, info.as_mut_ptr()) == 0 { + None + } else { + Some(info.assume_init()) + } + }; + info.map(|inf| Size { + rows: (inf.srWindow.Bottom - inf.srWindow.Top + 1) as u16, + cols: (inf.srWindow.Right - inf.srWindow.Left + 1) as u16, + }) +} |