diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 56f9a708fee65..e7d57c7ba0126 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -19,6 +19,7 @@ use syntax::parse::token; use syntax::parse; use syntax::symbol::Symbol; use syntax::feature_gate::UnstableFeatures; +use errors::emitter::HumanReadableErrorType; use errors::{ColorConfig, FatalError, Handler}; @@ -204,19 +205,18 @@ impl OutputType { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ErrorOutputType { - HumanReadable(ColorConfig), + HumanReadable(HumanReadableErrorType), 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, + /// The way the `rendered` field is created + json_rendered: HumanReadableErrorType, }, - Short(ColorConfig), } impl Default for ErrorOutputType { fn default() -> ErrorOutputType { - ErrorOutputType::HumanReadable(ColorConfig::Auto) + ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)) } } @@ -1350,8 +1350,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "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"), + json_rendered: Option = (None, parse_opt_string, [UNTRACKED], + "describes how to render 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], @@ -1807,9 +1807,9 @@ pub fn rustc_optgroups() -> Vec { ), opt::opt( "", - "colorful-json", - "Emit ansi color codes to the `rendered` field of json diagnostics", - "TYPE", + "json-rendered", + "Choose `rendered` field of json diagnostics render scheme", + "plain|termcolor", ), opt::opt_s( "", @@ -1951,7 +1951,17 @@ pub fn build_session_options_and_crate_config( ) } - let colorful_rendered = matches.opt_present("colorful-json"); + let json_rendered = matches.opt_str("json-rendered").and_then(|s| match s.as_str() { + "plain" => None, + "termcolor" => Some(HumanReadableErrorType::Default(ColorConfig::Always)), + _ => early_error( + ErrorOutputType::default(), + &format!( + "argument for --json-rendered must be `plain` or `termcolor` (instead was `{}`)", + s, + ), + ), + }).unwrap_or(HumanReadableErrorType::Default(ColorConfig::Never)); // 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 @@ -1959,14 +1969,14 @@ pub fn build_session_options_and_crate_config( // opt_present because the latter will panic. 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 { pretty: false, colorful_rendered }, - Some("pretty-json") => ErrorOutputType::Json { pretty: true, colorful_rendered }, - Some("short") => ErrorOutputType::Short(color), - None => ErrorOutputType::HumanReadable(color), + None | + Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), + Some("json") => ErrorOutputType::Json { pretty: false, json_rendered }, + Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered }, + Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), Some(arg) => early_error( - ErrorOutputType::HumanReadable(color), + ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), &format!( "argument for --error-format must be `human`, `json` or \ `short` (instead was `{}`)", @@ -1975,7 +1985,7 @@ pub fn build_session_options_and_crate_config( ), } } else { - ErrorOutputType::HumanReadable(color) + ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)) }; let unparsed_crate_types = matches.opt_strs("crate-type"); @@ -1988,12 +1998,12 @@ pub fn build_session_options_and_crate_config( let mut debugging_opts = build_debugging_options(matches, error_format); if !debugging_opts.unstable_options { - if colorful_rendered { - early_error(error_format, "--colorful-json=true is unstable"); + if matches.opt_str("json-rendered").is_some() { + early_error(error_format, "`--json-rendered=x` is unstable"); } - if let ErrorOutputType::Json { pretty: true, .. } = error_format { + if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format { early_error( - ErrorOutputType::Json { pretty: false, colorful_rendered: false }, + ErrorOutputType::Json { pretty: false, json_rendered }, "--error-format=pretty-json is unstable", ); } @@ -2902,7 +2912,7 @@ mod tests { const JSON: super::ErrorOutputType = super::ErrorOutputType::Json { pretty: false, - colorful_rendered: false, + json_rendered: super::HumanReadableErrorType::Default(super::ColorConfig::Never), }; // Reference diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 88eee1cd306d5..6a0e5d984789f 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -1037,44 +1037,42 @@ fn default_emitter( emitter_dest: Option>, ) -> Box { match (sopts.error_format, emitter_dest) { - (config::ErrorOutputType::HumanReadable(color_config), None) => Box::new( - EmitterWriter::stderr( - color_config, - Some(source_map.clone()), - false, - sopts.debugging_opts.teach, - ).ui_testing(sopts.debugging_opts.ui_testing), - ), - (config::ErrorOutputType::HumanReadable(_), Some(dst)) => Box::new( - 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, colorful_rendered }, None) => Box::new( + (config::ErrorOutputType::HumanReadable(kind), dst) => { + let (short, color_config) = kind.unzip(); + let emitter = match dst { + None => EmitterWriter::stderr( + color_config, + Some(source_map.clone()), + short, + sopts.debugging_opts.teach, + ), + Some(dst) => EmitterWriter::new( + dst, + Some(source_map.clone()), + short, + false, + color_config.suggests_using_colors(), + ), + }; + Box::new(emitter.ui_testing(sopts.debugging_opts.ui_testing)) + }, + (config::ErrorOutputType::Json { pretty, json_rendered }, None) => Box::new( JsonEmitter::stderr( Some(registry), source_map.clone(), pretty, - colorful_rendered, + json_rendered, ).ui_testing(sopts.debugging_opts.ui_testing), ), - (config::ErrorOutputType::Json { pretty, colorful_rendered }, Some(dst)) => Box::new( + (config::ErrorOutputType::Json { pretty, json_rendered }, Some(dst)) => Box::new( JsonEmitter::new( dst, Some(registry), source_map.clone(), pretty, - colorful_rendered, + json_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, sopts.debugging_opts.colorful_json, - )) - } } } @@ -1319,14 +1317,12 @@ pub enum IncrCompSession { pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { let emitter: Box = match output { - config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, false, false)) - } - 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)) + config::ErrorOutputType::HumanReadable(kind) => { + let (short, color_config) = kind.unzip(); + Box::new(EmitterWriter::stderr(color_config, None, short, false)) } + config::ErrorOutputType::Json { pretty, json_rendered } => + Box::new(JsonEmitter::basic(pretty, json_rendered)), }; let handler = errors::Handler::with_emitter(true, None, emitter); handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal); @@ -1335,14 +1331,12 @@ pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let emitter: Box = match output { - config::ErrorOutputType::HumanReadable(color_config) => { - Box::new(EmitterWriter::stderr(color_config, None, false, false)) - } - 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)) + config::ErrorOutputType::HumanReadable(kind) => { + let (short, color_config) = kind.unzip(); + Box::new(EmitterWriter::stderr(color_config, None, short, false)) } + config::ErrorOutputType::Json { pretty, json_rendered } => + Box::new(JsonEmitter::basic(pretty, json_rendered)), }; let handler = errors::Handler::with_emitter(true, None, emitter); handler.emit(&MultiSpan::new(), msg, errors::Level::Warning); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 0790f9bc76146..5ba17d12d9384 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -19,6 +19,32 @@ use std::cmp::{min, Reverse}; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; +/// Describes the way the content of the `rendered` field of the json output is generated +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum HumanReadableErrorType { + Default(ColorConfig), + Short(ColorConfig), +} + +impl HumanReadableErrorType { + /// Returns a (`short`, `color`) tuple + pub fn unzip(self) -> (bool, ColorConfig) { + match self { + HumanReadableErrorType::Default(cc) => (false, cc), + HumanReadableErrorType::Short(cc) => (true, cc), + } + } + pub fn new_emitter( + self, + dst: Box, + source_map: Option>, + teach: bool, + ) -> EmitterWriter { + let (short, color_config) = self.unzip(); + EmitterWriter::new(dst, source_map, short, teach, color_config.suggests_using_colors()) + } +} + const ANONYMIZED_LINE_NUM: &str = "LL"; /// Emitter trait for emitting errors. @@ -104,8 +130,8 @@ pub enum ColorConfig { } impl ColorConfig { - fn to_color_choice(&self) -> ColorChoice { - match *self { + fn to_color_choice(self) -> ColorChoice { + match self { ColorConfig::Always => { if atty::is(atty::Stream::Stderr) { ColorChoice::Always @@ -120,6 +146,14 @@ impl ColorConfig { ColorConfig::Auto => ColorChoice::Never, } } + pub fn suggests_using_colors(self) -> bool { + match self { + | ColorConfig::Always + | ColorConfig::Auto + => true, + ColorConfig::Never => false, + } + } } pub struct EmitterWriter { @@ -1540,6 +1574,7 @@ fn emit_to_destination(rendered_buffer: &[Vec], pub enum Destination { Terminal(StandardStream), Buffered(BufferWriter), + // The bool denotes whether we should be emitting ansi color codes or not Raw(Box<(dyn Write + Send)>, bool), } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index af5c95ea58996..a2acb02c339f8 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -3,7 +3,7 @@ use std::fmt; use std::path::PathBuf; use errors; -use errors::emitter::ColorConfig; +use errors::emitter::{ColorConfig, HumanReadableErrorType}; use getopts; use rustc::lint::Level; use rustc::session::early_error; @@ -256,11 +256,17 @@ impl Options { }; // FIXME: deduplicate this code from the identical code in librustc/session/config.rs let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) { - Some("human") => ErrorOutputType::HumanReadable(color), - Some("json") => ErrorOutputType::Json { pretty: false, colorful_rendered: false }, - Some("pretty-json") => ErrorOutputType::Json { pretty: true, colorful_rendered: false }, - Some("short") => ErrorOutputType::Short(color), - None => ErrorOutputType::HumanReadable(color), + None | + Some("human") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), + Some("json") => ErrorOutputType::Json { + pretty: false, + json_rendered: HumanReadableErrorType::Default(color), + }, + Some("pretty-json") => ErrorOutputType::Json { + pretty: true, + json_rendered: HumanReadableErrorType::Default(color), + }, + Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)), Some(arg) => { early_error(ErrorOutputType::default(), &format!("argument for --error-format must be `human`, `json` or \ diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 18bb5eef538ba..c141b47481531 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -299,15 +299,18 @@ pub fn new_handler(error_format: ErrorOutputType, // stick to the defaults let sessopts = Options::default(); let emitter: Box = match error_format { - ErrorOutputType::HumanReadable(color_config) => Box::new( - EmitterWriter::stderr( - color_config, - source_map.map(|cm| cm as _), - false, - sessopts.debugging_opts.teach, - ).ui_testing(ui_testing) - ), - ErrorOutputType::Json { pretty, colorful_rendered } => { + ErrorOutputType::HumanReadable(kind) => { + let (short, color_config) = kind.unzip(); + Box::new( + EmitterWriter::stderr( + color_config, + source_map.map(|cm| cm as _), + short, + sessopts.debugging_opts.teach, + ).ui_testing(ui_testing) + ) + }, + ErrorOutputType::Json { pretty, json_rendered } => { let source_map = source_map.unwrap_or_else( || Lrc::new(source_map::SourceMap::new(sessopts.file_path_mapping()))); Box::new( @@ -315,17 +318,10 @@ pub fn new_handler(error_format: ErrorOutputType, None, source_map, pretty, - colorful_rendered, + json_rendered, ).ui_testing(ui_testing) ) }, - ErrorOutputType::Short(color_config) => Box::new( - EmitterWriter::stderr( - color_config, - source_map.map(|cm| cm as _), - true, - false) - ), }; errors::Handler::with_emitter_and_flags( diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 55005a821b274..e08deaf2dede4 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -14,7 +14,7 @@ use crate::source_map::{SourceMap, FilePathMapping}; use errors::registry::Registry; use errors::{DiagnosticBuilder, SubDiagnostic, CodeSuggestion, SourceMapper}; use errors::{DiagnosticId, Applicability}; -use errors::emitter::{Emitter, EmitterWriter}; +use errors::emitter::{Emitter, HumanReadableErrorType}; use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan}; use rustc_data_structures::sync::{self, Lrc}; @@ -30,7 +30,7 @@ pub struct JsonEmitter { sm: Lrc, pretty: bool, ui_testing: bool, - colorful_rendered: bool, + json_rendered: HumanReadableErrorType, } impl JsonEmitter { @@ -38,7 +38,7 @@ impl JsonEmitter { registry: Option, source_map: Lrc, pretty: bool, - colorful_rendered: bool, + json_rendered: HumanReadableErrorType, ) -> JsonEmitter { JsonEmitter { dst: Box::new(io::stderr()), @@ -46,14 +46,14 @@ impl JsonEmitter { sm: source_map, pretty, ui_testing: false, - colorful_rendered, + json_rendered, } } - pub fn basic(pretty: bool, colorful_rendered: bool) -> JsonEmitter { + pub fn basic(pretty: bool, json_rendered: HumanReadableErrorType) -> JsonEmitter { let file_path_mapping = FilePathMapping::empty(); JsonEmitter::stderr(None, Lrc::new(SourceMap::new(file_path_mapping)), - pretty, colorful_rendered) + pretty, json_rendered) } pub fn new( @@ -61,7 +61,7 @@ impl JsonEmitter { registry: Option, source_map: Lrc, pretty: bool, - colorful_rendered: bool, + json_rendered: HumanReadableErrorType, ) -> JsonEmitter { JsonEmitter { dst, @@ -69,7 +69,7 @@ impl JsonEmitter { sm: source_map, pretty, ui_testing: false, - colorful_rendered, + json_rendered, } } @@ -199,7 +199,7 @@ impl Diagnostic { } let buf = BufWriter::default(); let output = buf.clone(); - EmitterWriter::new(Box::new(buf), Some(je.sm.clone()), false, false, je.colorful_rendered) + je.json_rendered.new_emitter(Box::new(buf), Some(je.sm.clone()), false) .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(); diff --git a/src/test/ui/lint/use_suggestion_json.rs b/src/test/ui/lint/use_suggestion_json.rs index 9cf3d0fa40301..d62f8f110e0e1 100644 --- a/src/test/ui/lint/use_suggestion_json.rs +++ b/src/test/ui/lint/use_suggestion_json.rs @@ -1,5 +1,5 @@ // ignore-cloudabi -// compile-flags: --error-format pretty-json -Zunstable-options --colorful-json=true +// compile-flags: --error-format pretty-json -Zunstable-options --json-rendered=termcolor // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/test/ui/lint/use_suggestion_json.stderr b/src/test/ui/lint/use_suggestion_json.stderr index 789bb5ea72f62..04cfebdd8013f 100644 --- a/src/test/ui/lint/use_suggestion_json.stderr +++ b/src/test/ui/lint/use_suggestion_json.stderr @@ -73,8 +73,8 @@ mod foo { "spans": [ { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 461, - "byte_end": 465, + "byte_start": 466, + "byte_end": 470, "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": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -124,8 +124,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -147,8 +147,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -170,8 +170,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -193,8 +193,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -216,8 +216,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -239,8 +239,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -262,8 +262,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -285,8 +285,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -308,8 +308,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -331,8 +331,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1, @@ -354,8 +354,8 @@ mod foo { }, { "file_name": "$DIR/use_suggestion_json.rs", - "byte_start": 438, - "byte_end": 438, + "byte_start": 443, + "byte_end": 443, "line_start": 10, "line_end": 10, "column_start": 1,