From af924d4ecfbb78d2d13e3204990c30baaa19469d Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 2 Jul 2020 12:00:54 +0100 Subject: [PATCH] Introduce `TtyWidth` This commit introduces a `TtyWidth` enum which enables better handling of the tty-width on Windows. Signed-off-by: David Wood --- src/cargo/core/compiler/mod.rs | 5 ++- src/cargo/core/shell.rs | 78 ++++++++++++++++++++-------------- src/cargo/util/progress.rs | 4 +- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 40445956586..91d444cce05 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -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)); diff --git a/src/cargo/core/shell.rs b/src/cargo/core/shell.rs index 63197f565ac..e155709e144 100644 --- a/src/cargo/core/shell.rs +++ b/src/cargo/core/shell.rs @@ -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 { + 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 { + 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 { + 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 { - 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 { - stderr_width() - } - - pub fn stderr_width() -> Option { + 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 fn accurate_stderr_width() -> Option { - None - } + pub(super) use super::{default_err_erase_line as err_erase_line, TtyWidth}; - pub fn stderr_width() -> Option { + 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)); + } + _ => (), } } diff --git a/src/cargo/util/progress.rs b/src/cargo/util/progress.rs index d62600379cb..76536b8d16d 100644 --- a/src/cargo/util/progress.rs +++ b/src/cargo/util/progress.rs @@ -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; } }