diff options
author | Devin Moore <devinmoore@google.com> | 2022-04-27 20:35:55 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-04-27 20:35:55 +0000 |
commit | 354dcc761ebc5e405b9ac91f0a74fbc0ea77f6c7 (patch) | |
tree | ee66490f633dc5a626bb20fe146335474ce2b304 | |
parent | 09a4caf8dfbff0896d0ce5bbfae2991bd147f35c (diff) | |
parent | 426ee43e9b0442f6fb0753b545a103d966fd17f2 (diff) | |
download | terminal-size-354dcc761ebc5e405b9ac91f0a74fbc0ea77f6c7.tar.gz |
Import terminal-size 0.17.0 am: 370a742066 am: 426ee43e9b
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/terminal-size/+/2076060
Change-Id: Ib8cd6d4270b2a69e0debae2605432774a19401f9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | Android.bp | 36 | ||||
-rw-r--r-- | Cargo.toml | 24 | ||||
l--------- | LICENSE | 1 | ||||
-rw-r--r-- | LICENSE-MIT | 19 | ||||
-rw-r--r-- | METADATA | 19 | ||||
-rw-r--r-- | MODULE_LICENSE_MIT | 0 | ||||
-rw-r--r-- | OWNERS | 1 | ||||
-rw-r--r-- | README.md | 41 | ||||
-rw-r--r-- | examples/get_size.rs | 49 | ||||
-rw-r--r-- | src/lib.rs | 37 | ||||
-rw-r--r-- | src/unix.rs | 117 | ||||
-rw-r--r-- | src/windows.rs | 53 |
12 files changed, 397 insertions, 0 deletions
diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..05c6e3b --- /dev/null +++ b/Android.bp @@ -0,0 +1,36 @@ +// This file is generated by cargo2android.py --run --device --tests --global_defaults=crosvm_defaults --add_workspace. +// Do not modify this file as changes will be overridden on upgrade. + +rust_library { + name: "libterminal_size", + defaults: ["crosvm_defaults"], + host_supported: true, + crate_name: "terminal_size", + cargo_env_compat: true, + cargo_pkg_version: "0.1.17", + srcs: ["src/lib.rs"], + edition: "2018", + rustlibs: [ + "liblibc", + ], +} + +rust_test { + name: "terminal-size_test_src_lib", + defaults: ["crosvm_defaults"], + host_supported: true, + crate_name: "terminal_size", + cargo_env_compat: true, + cargo_pkg_version: "0.1.17", + srcs: ["src/lib.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + // TODO(b/230624876) enable the test once it passes + unit_test: false, + }, + edition: "2018", + rustlibs: [ + "liblibc", + ], +} diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..d21a783 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "terminal_size" +version = "0.1.17" +authors = ["Andrew Chin <achin@eminence32.net>"] +description = "Gets the size of your Linux or Windows terminal" +documentation = "http://eminence.github.io/terminal-size/doc/terminal_size/index.html" +repository = "https://github.com/eminence/terminal-size" +keywords = ["terminal", "console", "term", "size", "dimensions"] +license = "MIT OR Apache-2.0" +edition = "2018" + + +[target.'cfg(not(windows))'.dependencies.libc] +version = "0.2" + +[target.'cfg(windows)'.dependencies.winapi] +version = "0.3" +features = [ + "handleapi", + "processenv", + "winbase", + "wincon", + "winnt", +] @@ -0,0 +1 @@ +LICENSE-MIT
\ No newline at end of file diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..a05bf27 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,19 @@ +Copyright (c) 2015 The terminal-size Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..8d7b96e --- /dev/null +++ b/METADATA @@ -0,0 +1,19 @@ +name: "terminal-size" +description: + "Gets the size of your Linux or Windows terminal" + +third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/terminal_size" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/terminal_size/terminal_size-0.1.17.crate" + } + version: "0.1.17." + last_upgrade_date { year: 2022 month: 4 day: 19 } + # This crate has the Apache 2 license and the MIT license. We have chosen to use the + # MIT license for use in Android. The Apache license file has been removed. + license_type: NOTICE +} diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_MIT @@ -0,0 +1 @@ +include platform/prebuilts/rust:/OWNERS diff --git a/README.md b/README.md new file mode 100644 index 0000000..bcaee60 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +terminal-size +============= + + +[Documention](https://docs.rs/crate/terminal_size) + + +Rust library to getting the size of your terminal. + +Works on Linux, MacOS, Windows, and illumos. + +```rust +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"); +} +``` + +## Minimum Rust Version + +This crate requires a minimum rust version of 1.31.0 (2018-12-06) + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/examples/get_size.rs b/examples/get_size.rs new file mode 100644 index 0000000..155784d --- /dev/null +++ b/examples/get_size.rs @@ -0,0 +1,49 @@ +#[cfg(windows)] +fn run() { + use std::os::windows::io::RawHandle; + use winapi::um::processenv::GetStdHandle; + use winapi::um::winbase::{STD_ERROR_HANDLE, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE}; + + let stdout = unsafe { GetStdHandle(STD_OUTPUT_HANDLE) } as RawHandle; + println!( + "Size from terminal_size_using_handle(stdout): {:?}", + terminal_size::terminal_size_using_handle(stdout) + ); + + let stderr = unsafe { GetStdHandle(STD_ERROR_HANDLE) } as RawHandle; + println!( + "Size from terminal_size_using_handle(stderr): {:?}", + terminal_size::terminal_size_using_handle(stderr) + ); + + let stdin = unsafe { GetStdHandle(STD_INPUT_HANDLE) } as RawHandle; + println!( + "Size from terminal_size_using_handle(stdin): {:?}", + terminal_size::terminal_size_using_handle(stdin) + ); +} + +#[cfg(not(windows))] +fn run() { + println!( + "Size from terminal_size_using_fd(stdout): {:?}", + terminal_size::terminal_size_using_fd(libc::STDOUT_FILENO) + ); + println!( + "Size from terminal_size_using_fd(stderr): {:?}", + terminal_size::terminal_size_using_fd(libc::STDERR_FILENO) + ); + println!( + "Size from terminal_size_using_fd(stdin): {:?}", + terminal_size::terminal_size_using_fd(libc::STDIN_FILENO) + ); +} + +fn main() { + println!( + "Size from terminal_size(): {:?}", + terminal_size::terminal_size() + ); + + run(); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..6ef79be --- /dev/null +++ b/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.31.0 (2018-12-06) +//! +//! # 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)] +pub struct Width(pub u16); +#[derive(Debug)] +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/src/unix.rs b/src/unix.rs new file mode 100644 index 0000000..59ac276 --- /dev/null +++ b/src/unix.rs @@ -0,0 +1,117 @@ +use super::{Height, Width}; +use std::os::unix::io::RawFd; + +/// 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(libc::STDOUT_FILENO) +} + +/// 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 libc::ioctl; + use libc::isatty; + use libc::{winsize as WinSize, TIOCGWINSZ}; + let is_tty: bool = unsafe { isatty(fd) == 1 }; + + if !is_tty { + return None; + } + + let mut winsize = WinSize { + ws_row: 0, + ws_col: 0, + ws_xpixel: 0, + ws_ypixel: 0, + }; + + if unsafe { ioctl(fd, TIOCGWINSZ.into(), &mut winsize) } == -1 { + return None; + } + + 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/src/windows.rs b/src/windows.rs new file mode 100644 index 0000000..14f487f --- /dev/null +++ b/src/windows.rs @@ -0,0 +1,53 @@ +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 winapi::um::processenv::GetStdHandle; + use winapi::um::winbase::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 winapi::um::handleapi::INVALID_HANDLE_VALUE; + use winapi::um::wincon::{ + GetConsoleScreenBufferInfo, CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT, + }; + + // convert between winapi::um::winnt::HANDLE and std::os::windows::raw::HANDLE + let hand = handle as winapi::um::winnt::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)) +} |