Skip to content

Commit

Permalink
Auto merge of #8427 - davidtwco:terminal-width, r=ehuss
Browse files Browse the repository at this point in the history
Add support for rustc's `-Z terminal-width`.

This PR continues the work started in #7315, adding support for rustc's `-Z terminal-width` flag, which is used to trim diagnostic output to fit within the current terminal and was added in rust-lang/rust#63402 (with JSON emitter support in rust-lang/rust#73763).

At the time of writing, rust-lang/rust#73763 isn't in nightly, so the test added in this PR will fail, but it should pass tomorrow (I've confirmed that it works with a local rustc build).

cc @estebank
  • Loading branch information
bors committed Jul 9, 2020
2 parents 62123e4 + af924d4 commit 0506d8d
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 20 deletions.
1 change: 1 addition & 0 deletions src/bin/cargo/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Available unstable (nightly-only) flags:
-Z timings -- Display concurrency information
-Z doctest-xcompile -- Compile and run doctests for non-host target using runner config
-Z crate-versions -- Add crate versions to generated docs
-Z terminal-width -- Provide a terminal width to rustc for error truncation
Run with 'cargo -Z [FLAG] [SUBCOMMAND]'"
);
Expand Down
22 changes: 22 additions & 0 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ pub use self::lto::Lto;
use self::output_depinfo::output_depinfo;
use self::unit_graph::UnitDep;
pub use crate::core::compiler::unit::{Unit, UnitInterner};
use crate::core::features::nightly_features_allowed;
use crate::core::manifest::TargetSourcePath;
use crate::core::profiles::{PanicStrategy, Profile, Strip};
use crate::core::{Edition, Feature, PackageId, Target};
Expand Down Expand Up @@ -709,13 +710,34 @@ fn add_error_format_and_color(
// to emit a message that cargo will intercept.
json.push_str(",artifacts");
}

match cx.bcx.build_config.message_format {
MessageFormat::Short | MessageFormat::Json { short: true, .. } => {
json.push_str(",diagnostic-short");
}
_ => {}
}
cmd.arg(json);

if nightly_features_allowed() {
let config = cx.bcx.config;
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));
}
// Terminal width was not explicitly provided but flag was provided - common case.
(Some(None), Some(width)) => {
cmd.arg(format!("-Zterminal-width={}", width));
}
// User didn't opt-in.
_ => (),
}
}

Ok(())
}

Expand Down
12 changes: 12 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ pub struct CliUnstable {
pub separate_nightlies: bool,
pub multitarget: bool,
pub rustdoc_map: bool,
pub terminal_width: Option<Option<usize>>,
}

impl CliUnstable {
Expand Down Expand Up @@ -411,6 +412,16 @@ impl CliUnstable {
Ok(true)
};

fn parse_usize_opt(value: Option<&str>) -> CargoResult<Option<usize>> {
Ok(match value {
Some(value) => match value.parse::<usize>() {
Ok(value) => Some(value),
Err(e) => bail!("expected a number, found: {}", e),
},
None => None,
})
}

match k {
"print-im-a-teapot" => self.print_im_a_teapot = parse_bool(k, v)?,
"unstable-options" => self.unstable_options = parse_empty(k, v)?,
Expand All @@ -437,6 +448,7 @@ impl CliUnstable {
"separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?,
"multitarget" => self.multitarget = parse_empty(k, v)?,
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
"terminal-width" => self.terminal_width = Some(parse_usize_opt(v)?),
_ => bail!("unknown `-Z` flag specified: {}", k),
}

Expand Down
61 changes: 45 additions & 16 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,12 +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,
_ => TtyWidth::NoTty,
}
}

Expand Down Expand Up @@ -408,21 +433,21 @@ impl ColorChoice {

#[cfg(unix)]
mod imp {
use super::Shell;
use super::{Shell, TtyWidth};
use std::mem;

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 @@ -445,14 +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 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 @@ -468,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 @@ -484,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
34 changes: 34 additions & 0 deletions src/doc/src/reference/unstable.md
Original file line number Diff line number Diff line change
Expand Up @@ -826,3 +826,37 @@ sysroot. If you are using rustup, this documentation can be installed with
The default value is `"remote"`.

The value may also take a URL for a custom location.

### terminal-width
This feature provides a new flag, `-Z terminal-width`, which is used to pass
a terminal width to `rustc` so that error messages containing long lines
can be intelligently truncated.

For example, passing `-Z terminal-width=20` (an arbitrarily low value) might
produce the following error:

```text
error[E0308]: mismatched types
--> src/main.rs:2:17
|
2 | ..._: () = 42;
| -- ^^ expected `()`, found integer
| |
| expected due to this
error: aborting due to previous error
```

In contrast, without `-Z terminal-width`, the error would look as shown below:

```text
error[E0308]: mismatched types
--> src/main.rs:2:17
|
2 | let _: () = 42;
| -- ^^ expected `()`, found integer
| |
| expected due to this
error: aborting due to previous error
```
28 changes: 26 additions & 2 deletions tests/testsuite/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use cargo::{
use cargo_test_support::paths::{root, CargoPathExt};
use cargo_test_support::registry::Package;
use cargo_test_support::{
basic_bin_manifest, basic_lib_manifest, basic_manifest, lines_match, main_file, project,
rustc_host, sleep_ms, symlink_supported, t, Execs, ProjectBuilder,
basic_bin_manifest, basic_lib_manifest, basic_manifest, is_nightly, lines_match, main_file,
project, rustc_host, sleep_ms, symlink_supported, t, Execs, ProjectBuilder,
};
use std::env;
use std::fs;
Expand Down Expand Up @@ -5103,3 +5103,27 @@ fn target_directory_backup_exclusion() {
p.cargo("build").run();
assert!(!&cachedir_tag.is_file());
}

#[cargo_test]
fn simple_terminal_width() {
if !is_nightly() {
// --terminal-width is unstable
return;
}
let p = project()
.file(
"src/lib.rs",
r#"
fn main() {
let _: () = 42;
}
"#,
)
.build();

p.cargo("build -Zterminal-width=20")
.masquerade_as_nightly_cargo()
.with_status(101)
.with_stderr_contains("3 | ..._: () = 42;")
.run();
}

0 comments on commit 0506d8d

Please sign in to comment.