Introduce TtyWidth

This commit introduces a `TtyWidth` enum which enables better handling
of the tty-width on Windows.

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-07-02 12:00:54 +01:00
parent 4177f66fd2
commit af924d4ecf
No known key found for this signature in database
GPG Key ID: 2592E76C87381FD9
3 changed files with 51 additions and 36 deletions

View File

@ -721,7 +721,10 @@ fn add_error_format_and_color(
if nightly_features_allowed() {
let config = cx.bcx.config;
match (config.cli_unstable().terminal_width, config.shell().accurate_err_width()) {
match (
config.cli_unstable().terminal_width,
config.shell().err_width().diagnostic_terminal_width(),
) {
// Terminal width explicitly provided - only useful for testing.
(Some(Some(width)), _) => {
cmd.arg(format!("-Zterminal-width={}", width));

View File

@ -6,6 +6,31 @@ use termcolor::{self, Color, ColorSpec, StandardStream, WriteColor};
use crate::util::errors::CargoResult;
pub enum TtyWidth {
NoTty,
Known(usize),
Guess(usize),
}
impl TtyWidth {
/// Returns the width provided with `-Z terminal-width` to rustc to truncate diagnostics with
/// long lines.
pub fn diagnostic_terminal_width(&self) -> Option<usize> {
match *self {
TtyWidth::NoTty | TtyWidth::Guess(_) => None,
TtyWidth::Known(width) => Some(width),
}
}
/// Returns the width used by progress bars for the tty.
pub fn progress_max_width(&self) -> Option<usize> {
match *self {
TtyWidth::NoTty => None,
TtyWidth::Known(width) | TtyWidth::Guess(width) => Some(width),
}
}
}
/// The requested verbosity of output.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
@ -125,21 +150,12 @@ impl Shell {
}
/// Returns the width of the terminal in spaces, if any.
pub fn err_width(&self) -> Option<usize> {
pub fn err_width(&self) -> TtyWidth {
match self.output {
ShellOut::Stream {
stderr_tty: true, ..
} => imp::stderr_width(),
_ => None,
}
}
/// Returns the width of the terminal in spaces, if any. Always `None` in Windows.
pub fn accurate_err_width(&self) -> Option<usize> {
if self.is_err_tty() {
imp::accurate_stderr_width()
} else {
None
_ => TtyWidth::NoTty,
}
}
@ -417,25 +433,21 @@ impl ColorChoice {
#[cfg(unix)]
mod imp {
use super::Shell;
use super::{Shell, TtyWidth};
use std::mem;
pub fn accurate_stderr_width() -> Option<usize> {
stderr_width()
}
pub fn stderr_width() -> Option<usize> {
pub fn stderr_width() -> TtyWidth {
unsafe {
let mut winsize: libc::winsize = mem::zeroed();
// The .into() here is needed for FreeBSD which defines TIOCGWINSZ
// as c_uint but ioctl wants c_ulong.
if libc::ioctl(libc::STDERR_FILENO, libc::TIOCGWINSZ.into(), &mut winsize) < 0 {
return None;
return TtyWidth::NoTty;
}
if winsize.ws_col > 0 {
Some(winsize.ws_col as usize)
TtyWidth::Known(winsize.ws_col as usize)
} else {
None
TtyWidth::NoTty
}
}
}
@ -458,18 +470,14 @@ mod imp {
use winapi::um::wincon::*;
use winapi::um::winnt::*;
pub(super) use super::default_err_erase_line as err_erase_line;
pub(super) use super::{default_err_erase_line as err_erase_line, TtyWidth};
pub fn accurate_stderr_width() -> Option<usize> {
None
}
pub fn stderr_width() -> Option<usize> {
pub fn stderr_width() -> TtyWidth {
unsafe {
let stdout = GetStdHandle(STD_ERROR_HANDLE);
let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
if GetConsoleScreenBufferInfo(stdout, &mut csbi) != 0 {
return Some((csbi.srWindow.Right - csbi.srWindow.Left) as usize);
return TtyWidth::Known((csbi.srWindow.Right - csbi.srWindow.Left) as usize);
}
// On mintty/msys/cygwin based terminals, the above fails with
@ -485,7 +493,7 @@ mod imp {
ptr::null_mut(),
);
if h == INVALID_HANDLE_VALUE {
return None;
return TtyWidth::NoTty;
}
let mut csbi: CONSOLE_SCREEN_BUFFER_INFO = mem::zeroed();
@ -501,17 +509,21 @@ mod imp {
// resize the console correctly, but there's no reasonable way
// to detect which kind of terminal we are running in, or if
// GetConsoleScreenBufferInfo returns accurate information.
return Some(cmp::min(60, width));
return TtyWidth::Guess(cmp::min(60, width));
}
None
TtyWidth::NoTty
}
}
}
#[cfg(windows)]
fn default_err_erase_line(shell: &mut Shell) {
if let Some(max_width) = imp::stderr_width() {
let blank = " ".repeat(max_width);
drop(write!(shell.output.stderr(), "{}\r", blank));
match imp::stderr_width() {
TtyWidth::Known(max_width) | TtyWidth::Guess(max_width) => {
let blank = " ".repeat(max_width);
drop(write!(shell.output.stderr(), "{}\r", blank));
}
_ => (),
}
}

View File

@ -50,7 +50,7 @@ impl<'cfg> Progress<'cfg> {
}
Progress {
state: cfg.shell().err_width().map(|n| State {
state: cfg.shell().err_width().progress_max_width().map(|n| State {
config: cfg,
format: Format {
style,
@ -216,7 +216,7 @@ impl<'cfg> State<'cfg> {
}
fn try_update_max_width(&mut self) {
if let Some(n) = self.config.shell().err_width() {
if let Some(n) = self.config.shell().err_width().progress_max_width() {
self.format.max_width = n;
}
}