Skip to content

Commit

Permalink
Introduce TtyWidth
Browse files Browse the repository at this point in the history
This commit introduces a `TtyWidth` enum which enables better handling
of the tty-width on Windows.

Signed-off-by: David Wood <david@davidtw.co>
  • Loading branch information
davidtwco committed Jul 9, 2020
1 parent 4177f66 commit af924d4
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 36 deletions.
5 changes: 4 additions & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
78 changes: 45 additions & 33 deletions src/cargo/core/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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
}
}
}
Expand All @@ -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<usize> {
None
}
pub(super) use super::{default_err_erase_line as err_erase_line, TtyWidth};

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
Expand All @@ -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();
Expand All @@ -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));
}
_ => (),
}
}
4 changes: 2 additions & 2 deletions src/cargo/util/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
}
Expand Down

0 comments on commit af924d4

Please sign in to comment.