From c23a6ddf3837c545129cbe2e4213cb25ef3b8d2e Mon Sep 17 00:00:00 2001 From: Canop Date: Fri, 1 Nov 2019 17:13:56 +0100 Subject: [PATCH] Add a tput based computation of terminal size (#283) --- CHANGELOG.md | 4 ++-- src/terminal/sys/unix.rs | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a6afbb..18bf866 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,10 +28,10 @@ - Rename `Attribute::NoInverse` to `NoReverse` - `Crossterm::style()` and `Crossterm::color()` - Remove re-exports from style module at at root and only expose those in the `crossterm::style` module. - - Remove `TerminalColor` (/style.rs), + - Remove `TerminalColor` (/style.rs), - Remove `color` (style.rs) - Update documentation - - Made `Colored` private, user should use commands instead. + - Made `Colored` private, user should use commands instead. - Rename `SetFg` -> `SetForegroundColor` - Rename `SetBg` -> `SetBackgroundColor` - Rename `SetAttr` -> `SetAttribute` diff --git a/src/terminal/sys/unix.rs b/src/terminal/sys/unix.rs index 009a55f..55d72ca 100644 --- a/src/terminal/sys/unix.rs +++ b/src/terminal/sys/unix.rs @@ -1,6 +1,6 @@ //! UNIX related logic for terminal manipulation. - use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}; +use std::process; use crate::utils::sys::unix::wrap_with_result; use crate::utils::Result; @@ -10,6 +10,39 @@ pub fn exit() { ::std::process::exit(0); } +/// execute tput with the given argument and parse +/// the output as a u16. +/// +/// The arg should be "cols" or "lines" +fn tput_value(arg: &str) -> Option { + match process::Command::new("tput").arg(arg).output() { + Ok(process::Output { stdout, .. }) => { + let value = stdout + .iter() + .map(|&b| b as u16) + .take_while(|&b| b >= 48 && b <= 58) + .fold(0, |v, b| v * 10 + (b - 48)); + if value > 0 { + Some(value) + } else { + None + } + } + _ => None, + } +} + +/// return the size of the screen as determined by tput +/// +/// This alternate way of computing the size is useful +/// when in a subshell. +fn tput_size() -> Option<(u16, u16)> { + match (tput_value("cols"), tput_value("lines")) { + (Some(w), Some(h)) => Some((w, h)), + _ => None, + } +} + /// Returns the terminal size `(columns, rows)`. /// /// The top left cell is represented `1,1`. @@ -26,6 +59,6 @@ pub fn size() -> Result<(u16, u16)> { { return Ok((size.ws_col, size.ws_row)); } else { - Err(std::io::Error::last_os_error().into()) + tput_size().ok_or_else(|| std::io::Error::last_os_error().into()) } }