Emit ansi color codes in the rendered field of json diagnostics

This commit is contained in:
Oliver Scherer 2019-03-12 13:06:43 +01:00
parent f694222887
commit 96404ee844
6 changed files with 123 additions and 80 deletions

View File

@ -205,7 +205,12 @@ pub fn extension(&self) -> &'static str {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ErrorOutputType {
HumanReadable(ColorConfig),
Json(bool),
Json {
/// Render the json in a human readable way (with indents and newlines)
pretty: bool,
/// The `rendered` field with the command line diagnostics include color codes
colorful_rendered: bool,
},
Short(ColorConfig),
}
@ -1345,6 +1350,8 @@ fn parse_merge_functions(slot: &mut Option<MergeFunctions>, v: Option<&str>) ->
"print some statistics about AST and HIR"),
always_encode_mir: bool = (false, parse_bool, [TRACKED],
"encode MIR of all functions into the crate metadata"),
colorful_json: bool = (false, parse_bool, [UNTRACKED],
"encode color codes in the `rendered` field of json diagnostics"),
unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED],
"take the breaks off const evaluation. NOTE: this is unsound"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
@ -1798,6 +1805,12 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
"How errors and other messages are produced",
"human|json|short",
),
opt::opt(
"",
"colorful-json",
"Emit ansi color codes to the `rendered` field of json diagnostics",
"TYPE",
),
opt::opt_s(
"",
"color",
@ -1938,6 +1951,7 @@ pub fn build_session_options_and_crate_config(
)
}
let colorful_rendered = matches.opt_present("colorful-json");
// We need the opts_present check because the driver will send us Matches
// with only stable options if no unstable options are used. Since error-format
@ -1946,8 +1960,8 @@ pub fn build_session_options_and_crate_config(
let error_format = if matches.opts_present(&["error-format".to_owned()]) {
match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
Some("human") => ErrorOutputType::HumanReadable(color),
Some("json") => ErrorOutputType::Json(false),
Some("pretty-json") => ErrorOutputType::Json(true),
Some("json") => ErrorOutputType::Json { pretty: false, colorful_rendered },
Some("pretty-json") => ErrorOutputType::Json { pretty: true, colorful_rendered },
Some("short") => ErrorOutputType::Short(color),
None => ErrorOutputType::HumanReadable(color),
@ -1973,11 +1987,16 @@ pub fn build_session_options_and_crate_config(
let mut debugging_opts = build_debugging_options(matches, error_format);
if !debugging_opts.unstable_options && error_format == ErrorOutputType::Json(true) {
early_error(
ErrorOutputType::Json(false),
"--error-format=pretty-json is unstable",
);
if !debugging_opts.unstable_options {
if colorful_rendered {
early_error(error_format, "--colorful-json=true is unstable");
}
if let ErrorOutputType::Json { pretty: true, .. } = error_format {
early_error(
ErrorOutputType::Json { pretty: false, colorful_rendered: false },
"--error-format=pretty-json is unstable",
);
}
}
if debugging_opts.pgo_gen.is_some() && !debugging_opts.pgo_use.is_empty() {

View File

@ -1046,29 +1046,34 @@ fn default_emitter(
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::HumanReadable(_), Some(dst)) => Box::new(
EmitterWriter::new(dst, Some(source_map.clone()), false, false)
.ui_testing(sopts.debugging_opts.ui_testing),
EmitterWriter::new(
dst, Some(source_map.clone()), false, false, sopts.debugging_opts.colorful_json,
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Json(pretty), None) => Box::new(
(config::ErrorOutputType::Json { pretty, colorful_rendered }, None) => Box::new(
JsonEmitter::stderr(
Some(registry),
source_map.clone(),
pretty,
colorful_rendered,
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new(
(config::ErrorOutputType::Json { pretty, colorful_rendered }, Some(dst)) => Box::new(
JsonEmitter::new(
dst,
Some(registry),
source_map.clone(),
pretty,
colorful_rendered,
).ui_testing(sopts.debugging_opts.ui_testing),
),
(config::ErrorOutputType::Short(color_config), None) => Box::new(
EmitterWriter::stderr(color_config, Some(source_map.clone()), true, false),
),
(config::ErrorOutputType::Short(_), Some(dst)) => {
Box::new(EmitterWriter::new(dst, Some(source_map.clone()), true, false))
Box::new(EmitterWriter::new(
dst, Some(source_map.clone()), true, false, sopts.debugging_opts.colorful_json,
))
}
}
}
@ -1317,7 +1322,8 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Json { pretty, colorful_rendered } =>
Box::new(JsonEmitter::basic(pretty, colorful_rendered)),
config::ErrorOutputType::Short(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, true, false))
}
@ -1332,7 +1338,8 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
config::ErrorOutputType::Json(pretty) => Box::new(JsonEmitter::basic(pretty)),
config::ErrorOutputType::Json { pretty, colorful_rendered } =>
Box::new(JsonEmitter::basic(pretty, colorful_rendered)),
config::ErrorOutputType::Short(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, true, false))
}

View File

@ -16,7 +16,7 @@
use std::io::prelude::*;
use std::io;
use std::cmp::{min, Reverse};
use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter};
use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi};
use termcolor::{WriteColor, Color, Buffer};
const ANONYMIZED_LINE_NUM: &str = "LL";
@ -152,13 +152,15 @@ pub fn stderr(color_config: ColorConfig,
}
}
pub fn new(dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMapperDyn>>,
short_message: bool,
teach: bool)
-> EmitterWriter {
pub fn new(
dst: Box<dyn Write + Send>,
source_map: Option<Lrc<SourceMapperDyn>>,
short_message: bool,
teach: bool,
colored: bool,
) -> EmitterWriter {
EmitterWriter {
dst: Raw(dst),
dst: Raw(dst, colored),
sm: source_map,
short_message,
teach,
@ -1538,13 +1540,14 @@ fn emit_to_destination(rendered_buffer: &[Vec<StyledString>],
pub enum Destination {
Terminal(StandardStream),
Buffered(BufferWriter),
Raw(Box<dyn Write + Send>),
Raw(Box<(dyn Write + Send)>, bool),
}
pub enum WritableDst<'a> {
Terminal(&'a mut StandardStream),
Buffered(&'a mut BufferWriter, Buffer),
Raw(&'a mut Box<dyn Write + Send>),
Raw(&'a mut (dyn Write + Send)),
ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
}
impl Destination {
@ -1570,7 +1573,8 @@ fn writable<'a>(&'a mut self) -> WritableDst<'a> {
let buf = t.buffer();
WritableDst::Buffered(t, buf)
}
Destination::Raw(ref mut t) => WritableDst::Raw(t),
Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
}
}
}
@ -1628,6 +1632,7 @@ fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> {
match *self {
WritableDst::Terminal(ref mut t) => t.set_color(color),
WritableDst::Buffered(_, ref mut t) => t.set_color(color),
WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
WritableDst::Raw(_) => Ok(())
}
}
@ -1636,6 +1641,7 @@ fn reset(&mut self) -> io::Result<()> {
match *self {
WritableDst::Terminal(ref mut t) => t.reset(),
WritableDst::Buffered(_, ref mut t) => t.reset(),
WritableDst::ColoredRaw(ref mut t) => t.reset(),
WritableDst::Raw(_) => Ok(()),
}
}
@ -1647,6 +1653,7 @@ fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
WritableDst::Terminal(ref mut t) => t.write(bytes),
WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
WritableDst::Raw(ref mut w) => w.write(bytes),
WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
}
}
@ -1655,6 +1662,7 @@ fn flush(&mut self) -> io::Result<()> {
WritableDst::Terminal(ref mut t) => t.flush(),
WritableDst::Buffered(_, ref mut buf) => buf.flush(),
WritableDst::Raw(ref mut w) => w.flush(),
WritableDst::ColoredRaw(ref mut w) => w.flush(),
}
}
}

View File

@ -30,37 +30,46 @@ pub struct JsonEmitter {
sm: Lrc<dyn SourceMapper + sync::Send + sync::Sync>,
pretty: bool,
ui_testing: bool,
colorful_rendered: bool,
}
impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
source_map: Lrc<SourceMap>,
pretty: bool) -> JsonEmitter {
pub fn stderr(
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
pretty: bool,
colorful_rendered: bool,
) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
sm: source_map,
pretty,
ui_testing: false,
colorful_rendered,
}
}
pub fn basic(pretty: bool) -> JsonEmitter {
pub fn basic(pretty: bool, colorful_rendered: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)),
pretty)
pretty, colorful_rendered)
}
pub fn new(dst: Box<dyn Write + Send>,
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
pretty: bool) -> JsonEmitter {
pub fn new(
dst: Box<dyn Write + Send>,
registry: Option<Registry>,
source_map: Lrc<SourceMap>,
pretty: bool,
colorful_rendered: bool,
) -> JsonEmitter {
JsonEmitter {
dst,
registry,
sm: source_map,
pretty,
ui_testing: false,
colorful_rendered,
}
}
@ -190,7 +199,7 @@ fn flush(&mut self) -> io::Result<()> {
}
let buf = BufWriter::default();
let output = buf.clone();
EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false)
EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false, je.colorful_rendered)
.ui_testing(je.ui_testing).emit(db);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap();

View File

@ -1,5 +1,5 @@
// ignore-cloudabi
// compile-flags: --error-format pretty-json -Zunstable-options
// compile-flags: --error-format pretty-json -Zunstable-options --colorful-json=true
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested

View File

@ -73,8 +73,8 @@ mod foo {
"spans": [
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 440,
"byte_end": 444,
"byte_start": 461,
"byte_end": 465,
"line_start": 11,
"line_end": 11,
"column_start": 12,
@ -101,8 +101,8 @@ mod foo {
"spans": [
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -124,8 +124,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -147,8 +147,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -170,8 +170,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -193,8 +193,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -216,8 +216,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -239,8 +239,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -262,8 +262,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -285,8 +285,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -308,8 +308,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -331,8 +331,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -354,8 +354,8 @@ mod foo {
},
{
"file_name": "$DIR/use_suggestion_json.rs",
"byte_start": 417,
"byte_end": 417,
"byte_start": 438,
"byte_end": 438,
"line_start": 10,
"line_end": 10,
"column_start": 1,
@ -380,22 +380,22 @@ mod foo {
"rendered": null
}
],
"rendered": "error[E0412]: cannot find type `Iter` in this scope
--> $DIR/use_suggestion_json.rs:11:12
|
LL | let x: Iter;
| ^^^^ not found in this scope
help: possible candidates are found in other modules, you can import them into scope
|
LL | use std::collections::binary_heap::Iter;
|
LL | use std::collections::btree_map::Iter;
|
LL | use std::collections::btree_set::Iter;
|
LL | use std::collections::hash_map::Iter;
|
and 8 other candidates
"rendered": "/u001b[0m/u001b[1m/u001b[38;5;9merror[E0412]/u001b[0m/u001b[0m/u001b[1m: cannot find type `Iter` in this scope/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m--> /u001b[0m/u001b[0m$DIR/use_suggestion_json.rs:11:12/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;12mLL/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0m let x: Iter;/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;9m^^^^/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;9mnot found in this scope/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;14mhelp/u001b[0m/u001b[0m: possible candidates are found in other modules, you can import them into scope/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;12mLL/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0muse std::collections::binary_heap::Iter;/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;12mLL/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0muse std::collections::btree_map::Iter;/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;12mLL/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0muse std::collections::btree_set::Iter;/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0m/u001b[1m/u001b[38;5;12mLL/u001b[0m/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m| /u001b[0m/u001b[0muse std::collections::hash_map::Iter;/u001b[0m
/u001b[0m /u001b[0m/u001b[0m/u001b[1m/u001b[38;5;12m|/u001b[0m
/u001b[0mand 8 other candidates/u001b[0m
"
}
@ -405,7 +405,7 @@ and 8 other candidates
"level": "error",
"spans": [],
"children": [],
"rendered": "error: aborting due to previous error
"rendered": "/u001b[0m/u001b[1m/u001b[38;5;9merror/u001b[0m/u001b[0m/u001b[1m: aborting due to previous error/u001b[0m
"
}
@ -415,6 +415,6 @@ and 8 other candidates
"level": "",
"spans": [],
"children": [],
"rendered": "For more information about this error, try `rustc --explain E0412`.
"rendered": "/u001b[0m/u001b[1mFor more information about this error, try `rustc --explain E0412`./u001b[0m
"
}