Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for rustc's -Z terminal-width. #8427

Merged
merged 4 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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() {
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
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();
}