Skip to content
This repository has been archived by the owner on Mar 10, 2021. It is now read-only.

Commit

Permalink
feat: allows getting the terminal size of all standard streams, or ju…
Browse files Browse the repository at this point in the history
…st particular ones

`dimensions` will now attempt to poll all three standard streams to find
the terminal size. `diminensions_{stdout,stderr,stdin}` have also been
added to only poll a particular stream.

`dimensions_stdout` is the equivilant of `term_size::dimensions` prior
to this release
  • Loading branch information
kbknapp committed Apr 9, 2017
1 parent 0297b6a commit c7095c9
Showing 1 changed file with 107 additions and 11 deletions.
118 changes: 107 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ extern crate kernel32;
#[cfg(target_os = "windows")]
extern crate winapi;

pub use platform::dimensions;
pub use platform::{dimensions, dimensions_stdout, dimensions_stdin, dimensions_stderr};

#[cfg(any(target_os = "linux",
target_os = "android",
Expand All @@ -33,7 +33,7 @@ pub use platform::dimensions;
target_os = "solaris"))]
mod platform {
use std::mem::zeroed;
use libc::{STDOUT_FILENO, c_int, c_ulong, winsize};
use libc::{STDOUT_FILENO, STDIN_FILENO, STDERR_FILENO, c_int, c_ulong, winsize};

// Unfortunately the actual command is not standardised...
#[cfg(any(target_os = "linux", target_os = "android"))]
Expand All @@ -55,24 +55,118 @@ mod platform {
fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

/// Runs the ioctl command. Returns (0, 0) if output is not to a terminal, or
/// Runs the ioctl command. Returns (0, 0) if all of the streams are not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions() -> winsize {
unsafe fn get_dimensions_any() -> winsize {
let mut window: winsize = zeroed();
let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);
let mut result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

if result == -1 {
zeroed()
} else {
window
window = zeroed();
result = ioctl(STDIN_FILENO, TIOCGWINSZ, &mut window);
if result == -1 {
window = zeroed();
result = ioctl(STDERR_FILENO, TIOCGWINSZ, &mut window);
if result == -1 {
return zeroed();
}
}
}
window
}

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
/// Runs the ioctl command. Returns (0, 0) if the output is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions_out() -> winsize {
let mut window: winsize = zeroed();
let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

if result != -1 {
return window;
}
zeroed()
}

/// Runs the ioctl command. Returns (0, 0) if the input is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions_in() -> winsize {
let mut window: winsize = zeroed();
let result = ioctl(STDIN_FILENO, TIOCGWINSZ, &mut window);

if result != -1 {
return window;
}
zeroed()
}

/// Runs the ioctl command. Returns (0, 0) if the error is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions_err() -> winsize {
let mut window: winsize = zeroed();
let result = ioctl(STDERR_FILENO, TIOCGWINSZ, &mut window);

if result != -1 {
return window;
}
zeroed()
}

/// Query the current processes's output (`stdout`), input (`stdin`), and error (`stderr`) in
/// that order, in the attempt to dtermine terminal width. If one of those streams is actually
/// a tty, this function returns its width and height as a number of characters.
///
/// If *all* of the streams are not ttys or return any errors this function will return `None`.
pub fn dimensions() -> Option<(usize, usize)> {
let w = unsafe { get_dimensions() };
let w = unsafe { get_dimensions_any() };

if w.ws_col == 0 || w.ws_row == 0 {
None
} else {
Some((w.ws_col as usize, w.ws_row as usize))
}
}

/// Query the current processes's output (`stdout`) *only*, in the attempt to dtermine
/// terminal width. If that streams is actually a tty, this function returns its width
/// and height as a number of characters.
///
/// If *all* of the streams are not ttys or return any errors this function will return `None`.
pub fn dimensions_stdout() -> Option<(usize, usize)> {
let w = unsafe { get_dimensions_out() };

if w.ws_col == 0 || w.ws_row == 0 {
None
} else {
Some((w.ws_col as usize, w.ws_row as usize))
}
}

/// Query the current processes's input (`stdin`) *only*, in the attempt to dtermine
/// terminal width. If that streams is actually a tty, this function returns its width
/// and height as a number of characters.
///
/// If *all* of the streams are not ttys or return any errors this function will return `None`.
pub fn dimensions_stdin() -> Option<(usize, usize)> {
let w = unsafe { get_dimensions_in() };

if w.ws_col == 0 || w.ws_row == 0 {
None
} else {
Some((w.ws_col as usize, w.ws_row as usize))
}
}

/// Query the current processes's error output (`stderr`) *only*, in the attempt to dtermine
/// terminal width. If that streams is actually a tty, this function returns its width
/// and height as a number of characters.
///
/// If *all* of the streams are not ttys or return any errors this function will return `None`.
pub fn dimensions_stderr() -> Option<(usize, usize)> {
let w = unsafe { get_dimensions_err() };

if w.ws_col == 0 || w.ws_row == 0 {
None
Expand All @@ -87,6 +181,8 @@ mod platform {
use kernel32::{GetConsoleScreenBufferInfo, GetStdHandle};
use winapi::{CONSOLE_SCREEN_BUFFER_INFO, COORD, SMALL_RECT, STD_OUTPUT_HANDLE};

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
pub fn dimensions() -> Option<(usize, usize)> {
let null_coord = COORD{
X: 0,
Expand Down

0 comments on commit c7095c9

Please sign in to comment.