diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
commit | 64d98f8ee037282c35007b64c2649055c56af1db (patch) | |
tree | 5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /vendor/terminal_size/src | |
parent | Adding debian version 1.67.1+dfsg1-1. (diff) | |
download | rustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/terminal_size/src')
-rw-r--r-- | vendor/terminal_size/src/lib.rs | 37 | ||||
-rw-r--r-- | vendor/terminal_size/src/unix.rs | 111 | ||||
-rw-r--r-- | vendor/terminal_size/src/windows.rs | 52 |
3 files changed, 200 insertions, 0 deletions
diff --git a/vendor/terminal_size/src/lib.rs b/vendor/terminal_size/src/lib.rs new file mode 100644 index 000000000..e933b2140 --- /dev/null +++ b/vendor/terminal_size/src/lib.rs @@ -0,0 +1,37 @@ +//! A simple utility for getting the size of a terminal. +//! +//! Supports both Linux, MacOS, and Windows. +//! +//! This crate requires a minimum rust version of 1.48.0 (2020-11-19) +//! +//! # Example +//! +//! ``` +//! use terminal_size::{Width, Height, terminal_size}; +//! +//! let size = terminal_size(); +//! if let Some((Width(w), Height(h))) = size { +//! println!("Your terminal is {} cols wide and {} lines tall", w, h); +//! } else { +//! println!("Unable to get terminal size"); +//! } +//! ``` +//! + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Width(pub u16); +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct Height(pub u16); + +#[cfg(unix)] +mod unix; +#[cfg(unix)] +pub use crate::unix::{terminal_size, terminal_size_using_fd}; + +#[cfg(windows)] +mod windows; +#[cfg(windows)] +pub use crate::windows::{terminal_size, terminal_size_using_handle}; + +#[cfg(not(any(unix, windows)))] +pub fn terminal_size() -> Option<(Width, Height)> { None } diff --git a/vendor/terminal_size/src/unix.rs b/vendor/terminal_size/src/unix.rs new file mode 100644 index 000000000..59af979d0 --- /dev/null +++ b/vendor/terminal_size/src/unix.rs @@ -0,0 +1,111 @@ +use super::{Height, Width}; +use std::os::unix::io::RawFd; +use rustix::fd::BorrowedFd; + +/// Returns the size of the terminal defaulting to STDOUT, if available. +/// +/// If STDOUT is not a tty, returns `None` +pub fn terminal_size() -> Option<(Width, Height)> { + terminal_size_using_fd(rustix::io::raw_stdout()) +} + +/// Returns the size of the terminal using the given file descriptor, if available. +/// +/// If the given file descriptor is not a tty, returns `None` +pub fn terminal_size_using_fd(fd: RawFd) -> Option<(Width, Height)> { + use rustix::termios::{isatty, tcgetwinsize}; + + // TODO: Once I/O safety is stabilized, the enlosing function here should + // be unsafe due to taking a `RawFd`. We should then move the main + // logic here into a new function which takes a `BorrowedFd` and is safe. + let fd = unsafe { BorrowedFd::borrow_raw(fd) }; + + if !isatty(fd) { + return None; + } + + let winsize = tcgetwinsize(fd).ok()?; + + let rows = winsize.ws_row; + let cols = winsize.ws_col; + + if rows > 0 && cols > 0 { + Some((Width(cols), Height(rows))) + } else { + None + } +} + +#[test] +/// Compare with the output of `stty size` +fn compare_with_stty() { + use std::process::Command; + use std::process::Stdio; + + let (rows, cols) = if cfg!(target_os = "illumos") { + // illumos stty(1) does not accept a device argument, instead using + // stdin unconditionally: + let output = Command::new("stty") + .stdin(Stdio::inherit()) + .output() + .unwrap(); + assert!(output.status.success()); + + // stdout includes the row and columns thus: "rows = 80; columns = 24;" + let vals = String::from_utf8(output.stdout) + .unwrap() + .lines() + .map(|line| { + // Split each line on semicolons to get "k = v" strings: + line.split(';') + .map(str::trim) + .map(str::to_string) + .collect::<Vec<_>>() + }) + .flatten() + .filter_map(|term| { + // split each "k = v" string and look for rows/columns: + match term.splitn(2, " = ").collect::<Vec<_>>().as_slice() { + ["rows", n] | ["columns", n] => Some(n.parse().unwrap()), + _ => None, + } + }) + .collect::<Vec<_>>(); + (vals[0], vals[1]) + } else { + let output = if cfg!(target_os = "linux") { + Command::new("stty") + .arg("size") + .arg("-F") + .arg("/dev/stderr") + .stderr(Stdio::inherit()) + .output() + .unwrap() + } else { + Command::new("stty") + .arg("-f") + .arg("/dev/stderr") + .arg("size") + .stderr(Stdio::inherit()) + .output() + .unwrap() + }; + + assert!(output.status.success()); + let stdout = String::from_utf8(output.stdout).unwrap(); + // stdout is "rows cols" + let mut data = stdout.split_whitespace(); + println!("{}", stdout); + let rows = u16::from_str_radix(data.next().unwrap(), 10).unwrap(); + let cols = u16::from_str_radix(data.next().unwrap(), 10).unwrap(); + (rows, cols) + }; + println!("{} {}", rows, cols); + + if let Some((Width(w), Height(h))) = terminal_size() { + assert_eq!(rows, h); + assert_eq!(cols, w); + } else { + panic!("terminal_size() return None"); + } +} diff --git a/vendor/terminal_size/src/windows.rs b/vendor/terminal_size/src/windows.rs new file mode 100644 index 000000000..74315d6ab --- /dev/null +++ b/vendor/terminal_size/src/windows.rs @@ -0,0 +1,52 @@ +use super::{Height, Width}; +use std::os::windows::io::RawHandle; + +/// Returns the size of the terminal defaulting to STDOUT, if available. +/// +/// Note that this returns the size of the actual command window, and +/// not the overall size of the command window buffer +pub fn terminal_size() -> Option<(Width, Height)> { + use windows_sys::Win32::System::Console::{GetStdHandle, STD_OUTPUT_HANDLE}; + + let handle = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) as RawHandle }; + + terminal_size_using_handle(handle) +} + +/// Returns the size of the terminal using the given handle, if available. +/// +/// If the given handle is not a tty, returns `None` +pub fn terminal_size_using_handle(handle: RawHandle) -> Option<(Width, Height)> { + use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; + use windows_sys::Win32::System::Console::{ + GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT, + }; + + // convert between windows_sys::Win32::Foundation::HANDLE and std::os::windows::raw::HANDLE + let hand = handle as windows_sys::Win32::Foundation::HANDLE; + + if hand == INVALID_HANDLE_VALUE { + return None; + } + + let zc = COORD { X: 0, Y: 0 }; + let mut csbi = CONSOLE_SCREEN_BUFFER_INFO { + dwSize: zc, + dwCursorPosition: zc, + wAttributes: 0, + srWindow: SMALL_RECT { + Left: 0, + Top: 0, + Right: 0, + Bottom: 0, + }, + dwMaximumWindowSize: zc, + }; + if unsafe { GetConsoleScreenBufferInfo(hand, &mut csbi) } == 0 { + return None; + } + + let w: Width = Width((csbi.srWindow.Right - csbi.srWindow.Left + 1) as u16); + let h: Height = Height((csbi.srWindow.Bottom - csbi.srWindow.Top + 1) as u16); + Some((w, h)) +} |