From 51fe9f9d035906977b2ff576c77adf12069d39a3 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Mon, 19 Jan 2015 08:59:52 -0800 Subject: [PATCH 1/2] Namespace use of diagnostic::ColorConfig With some other cleanup at the use sites. --- src/librustc/session/config.rs | 12 ++++++------ src/librustc/session/mod.rs | 10 ++++++---- src/librustc_back/target/mod.rs | 2 +- src/librustc_driver/lib.rs | 4 ++-- src/libsyntax/diagnostic.rs | 7 +++---- src/libsyntax/parse/mod.rs | 5 +++-- 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index d9bb1d769bfbe..4fe5ef1c95945 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -29,7 +29,7 @@ use syntax::ast; use syntax::ast::{IntTy, UintTy}; use syntax::attr; use syntax::attr::AttrMetaMethods; -use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler}; +use syntax::diagnostic::{ColorConfig, SpanHandler}; use syntax::parse; use syntax::parse::token::InternedString; @@ -228,7 +228,7 @@ pub fn basic_options() -> Options { write_dependency_info: (false, None), prints: Vec::new(), cg: basic_codegen_options(), - color: Auto, + color: ColorConfig::Auto, show_span: None, externs: HashMap::new(), crate_name: None, @@ -1073,11 +1073,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } let color = match matches.opt_str("color").as_ref().map(|s| &s[]) { - Some("auto") => Auto, - Some("always") => Always, - Some("never") => Never, + Some("auto") => ColorConfig::Auto, + Some("always") => ColorConfig::Always, + Some("never") => ColorConfig::Never, - None => Auto, + None => ColorConfig::Auto, Some(arg) => { early_error(&format!("argument for --color must be auto, always \ diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 5424b1c8cae50..35a6a17d556b6 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -365,13 +365,15 @@ pub fn expect(sess: &Session, opt: Option, msg: M) -> T where diagnostic::expect(sess.diagnostic(), opt, msg) } +pub fn fallback_emitter() -> diagnostic::EmitterWriter { + diagnostic::EmitterWriter::stderr(diagnostic::ColorConfig::Auto, None) +} + pub fn early_error(msg: &str) -> ! { - let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); - emitter.emit(None, msg, None, diagnostic::Fatal); + fallback_emitter().emit(None, msg, None, diagnostic::Fatal); panic!(diagnostic::FatalError); } pub fn early_warn(msg: &str) { - let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); - emitter.emit(None, msg, None, diagnostic::Warning); + fallback_emitter().emit(None, msg, None, diagnostic::Warning); } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index f8eabb4375fb3..efb9db9094769 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -222,7 +222,7 @@ impl Target { // this is 1. ugly, 2. error prone. - let handler = diagnostic::default_handler(diagnostic::Auto, None); + let handler = diagnostic::default_handler(diagnostic::ColorConfig::Auto, None); let get_req_field = |&: name: &str| { match obj.find(name) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 50ff4546c3783..8d493486905e9 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -71,7 +71,7 @@ use std::os; use std::sync::mpsc::channel; use std::thread; -use rustc::session::early_error; +use rustc::session::{early_error, fallback_emitter}; use syntax::ast; use syntax::parse; @@ -616,7 +616,7 @@ pub fn monitor(f: F) { Err(value) => { // Thread panicked without emitting a fatal diagnostic if !value.is::() { - let mut emitter = diagnostic::EmitterWriter::stderr(diagnostic::Auto, None); + let mut emitter = fallback_emitter(); // a .span_bug or .bug call has already printed what // it wants to print. diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 7213b0fa9556c..638f8f8925d28 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -10,7 +10,6 @@ pub use self::Level::*; pub use self::RenderSpan::*; -pub use self::ColorConfig::*; use self::Destination::*; use codemap::{COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; @@ -335,9 +334,9 @@ impl EmitterWriter { let stderr = io::stderr(); let use_color = match color_config { - Always => true, - Never => false, - Auto => stderr.get_ref().isatty() + ColorConfig::Always => true, + ColorConfig::Never => false, + ColorConfig::Auto => stderr.get_ref().isatty() }; if use_color { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 90e236dfde35b..7dd7035f769e1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast; use codemap::{Span, CodeMap, FileMap}; -use diagnostic::{SpanHandler, mk_span_handler, default_handler, Auto}; +use diagnostic::{SpanHandler, mk_span_handler, default_handler, ColorConfig}; use parse::attr::ParserAttr; use parse::parser::Parser; use ptr::P; @@ -45,7 +45,8 @@ pub struct ParseSess { pub fn new_parse_sess() -> ParseSess { ParseSess { - span_diagnostic: mk_span_handler(default_handler(Auto, None), CodeMap::new()), + span_diagnostic: mk_span_handler(default_handler(ColorConfig::Auto, None), + CodeMap::new()), included_mod_stack: RefCell::new(Vec::new()), node_id: Cell::new(1), } From f2501102a1034e1ebd05faf89a6361c9a35dce26 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Mon, 19 Jan 2015 12:57:52 -0800 Subject: [PATCH 2/2] Add rustc --drawing to use Unicode line drawing characters for span output I bet we can find other uses for these sorts of characters in clarifying type errors, etc. This is marked as a "stable" flag for consistency with --color. However we should reconsider both of them as part of #19051. For these features to be conveniently available with Cargo, we may want to use environment variables or a config file. --- man/rustc.1 | 3 + src/etc/zsh/_rust | 1 + src/librustc/session/config.rs | 35 ++++---- src/librustc/session/mod.rs | 5 +- src/librustc_back/target/mod.rs | 2 +- src/librustdoc/core.rs | 3 +- src/librustdoc/test.rs | 3 +- src/libsyntax/diagnostic.rs | 79 +++++++++++++++---- src/libsyntax/parse/mod.rs | 5 +- .../compile-fail/drawing-spans-one-char.rs | 18 +++++ src/test/compile-fail/drawing-spans.rs | 18 +++++ 11 files changed, 136 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/drawing-spans-one-char.rs create mode 100644 src/test/compile-fail/drawing-spans.rs diff --git a/man/rustc.1 b/man/rustc.1 index 3d8b27a408a27..513a019f567fc 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -100,6 +100,9 @@ Configure coloring of output: auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output +.TP +\fB\-\-drawing\fR +Use drawing characters in diagnostic output .SH CODEGEN OPTIONS diff --git a/src/etc/zsh/_rust b/src/etc/zsh/_rust index 404f622f970c3..ff54c84b90e8a 100644 --- a/src/etc/zsh/_rust +++ b/src/etc/zsh/_rust @@ -67,6 +67,7 @@ _rustc_opts_switches=( {-V,--verbose}'[use verbose output]' -O'[Equivalent to -C opt-level=2]' --test'[Build a test harness]' + --drawing'[Use drawing characters in diagnostic output]' ) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 4fe5ef1c95945..5d7075b264b72 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -29,6 +29,7 @@ use syntax::ast; use syntax::ast::{IntTy, UintTy}; use syntax::attr; use syntax::attr::AttrMetaMethods; +use syntax::diagnostic; use syntax::diagnostic::{ColorConfig, SpanHandler}; use syntax::parse; use syntax::parse::token::InternedString; @@ -37,6 +38,7 @@ use std::collections::HashMap; use std::collections::hash_map::Entry::{Occupied, Vacant}; use getopts; use std::fmt; +use std::default; use llvm; @@ -104,7 +106,7 @@ pub struct Options { pub write_dependency_info: (bool, Option), pub prints: Vec, pub cg: CodegenOptions, - pub color: ColorConfig, + pub emit_cfg: diagnostic::EmitterConfig, pub show_span: Option, pub externs: HashMap>, pub crate_name: Option, @@ -228,7 +230,7 @@ pub fn basic_options() -> Options { write_dependency_info: (false, None), prints: Vec::new(), cg: basic_codegen_options(), - color: ColorConfig::Auto, + emit_cfg: default::Default::default(), show_span: None, externs: HashMap::new(), crate_name: None, @@ -793,6 +795,7 @@ pub fn rustc_optgroups() -> Vec { auto = colorize, if output goes to a tty (default); always = always colorize output; never = never colorize output", "auto|always|never"), + opt::flag("", "drawing", "Use drawing characters in diagnostic output"), // DEPRECATED opt::flag("", "print-crate-name", "Output the crate name and exit"), @@ -1072,19 +1075,21 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { --debuginfo"); } - let color = match matches.opt_str("color").as_ref().map(|s| &s[]) { - Some("auto") => ColorConfig::Auto, - Some("always") => ColorConfig::Always, - Some("never") => ColorConfig::Never, - - None => ColorConfig::Auto, - - Some(arg) => { - early_error(&format!("argument for --color must be auto, always \ - or never (instead was `{}`)", - arg)[]) - } + let mut emit_cfg: diagnostic::EmitterConfig = default::Default::default(); + if let Some(arg) = matches.opt_str("color").as_ref() { + emit_cfg.color = match &arg[] { + "auto" => ColorConfig::Auto, + "always" => ColorConfig::Always, + "never" => ColorConfig::Never, + _ => { + early_error(&format!("argument for --color must be auto, always \ + or never (instead was `{}`)", arg)[]); + } + }; }; + if matches.opt_present("drawing") { + emit_cfg.drawing = true; + } let mut externs = HashMap::new(); for arg in matches.opt_strs("extern").iter() { @@ -1126,7 +1131,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { write_dependency_info: write_dependency_info, prints: prints, cg: cg, - color: color, + emit_cfg: emit_cfg, show_span: None, externs: externs, crate_name: crate_name, diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 35a6a17d556b6..bf44cef1dcd0b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -31,6 +31,7 @@ use rustc_back::target::Target; use std::os; use std::cell::{Cell, RefCell}; +use std::default::Default; pub mod config; pub mod search_paths; @@ -291,7 +292,7 @@ pub fn build_session(sopts: config::Options, -> Session { let codemap = codemap::CodeMap::new(); let diagnostic_handler = - diagnostic::default_handler(sopts.color, Some(registry)); + diagnostic::default_handler(sopts.emit_cfg, Some(registry)); let span_diagnostic_handler = diagnostic::mk_span_handler(diagnostic_handler, codemap); @@ -366,7 +367,7 @@ pub fn expect(sess: &Session, opt: Option, msg: M) -> T where } pub fn fallback_emitter() -> diagnostic::EmitterWriter { - diagnostic::EmitterWriter::stderr(diagnostic::ColorConfig::Auto, None) + diagnostic::EmitterWriter::stderr(Default::default(), None) } pub fn early_error(msg: &str) -> ! { diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index efb9db9094769..8c793fbd02753 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -222,7 +222,7 @@ impl Target { // this is 1. ugly, 2. error prone. - let handler = diagnostic::default_handler(diagnostic::ColorConfig::Auto, None); + let handler = diagnostic::default_handler(Default::default(), None); let get_req_field = |&: name: &str| { match obj.find(name) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 5bef0195874b6..887e8e6997805 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -22,6 +22,7 @@ use syntax::{ast, ast_map, codemap, diagnostic}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; +use std::default::Default; use visit_ast::RustdocVisitor; use clean; @@ -103,7 +104,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, }; let codemap = codemap::CodeMap::new(); - let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None); + let diagnostic_handler = diagnostic::default_handler(Default::default(), None); let span_diagnostic_handler = diagnostic::mk_span_handler(diagnostic_handler, codemap); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 9b8d220acc394..d953e52a706fb 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -17,6 +17,7 @@ use std::os; use std::str; use std::thread::Thread; use std::thunk::Thunk; +use std::default::Default; use std::collections::{HashSet, HashMap}; use testing; @@ -58,7 +59,7 @@ pub fn run(input: &str, }; let codemap = CodeMap::new(); - let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None); + let diagnostic_handler = diagnostic::default_handler(Default::default(), None); let span_diagnostic_handler = diagnostic::mk_span_handler(diagnostic_handler, codemap); diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 638f8f8925d28..a82890c56a0c2 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -21,6 +21,7 @@ use std::fmt; use std::io; use std::iter::range; use std::string::String; +use std::default::Default; use term::WriterWrapper; use term; @@ -60,6 +61,49 @@ pub enum ColorConfig { Never } +#[derive(Clone, Copy)] +pub struct EmitterConfig { + pub color: ColorConfig, + pub drawing: bool, +} + +impl Default for EmitterConfig { + fn default() -> EmitterConfig { + EmitterConfig { + color: ColorConfig::Auto, + drawing: false, + } + } +} + +#[derive(Clone, Copy)] +struct SpanFormat { + single: char, + begin: char, + middle: char, + end: char, +} + +impl EmitterConfig { + #[inline] + fn span_format(&self) -> SpanFormat { + match self.drawing { + false => SpanFormat { + single: '^', + begin: '^', + middle: '~', + end: '~', + }, + true => SpanFormat { + single: '\u{25B2}', // BLACK UP-POINTING TRIANGLE + begin: '\u{2517}', // BOX DRAWINGS HEAVY UP AND RIGHT + middle: '\u{2501}', // BOX DRAWINGS HEAVY HORIZONTAL + end: '\u{251B}', // BOX DRAWINGS HEAVY UP AND LEFT + }, + } + } +} + pub trait Emitter { fn emit(&mut self, cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, code: Option<&str>, lvl: Level); @@ -212,9 +256,9 @@ pub fn mk_span_handler(handler: Handler, cm: codemap::CodeMap) -> SpanHandler { } } -pub fn default_handler(color_config: ColorConfig, +pub fn default_handler(cfg: EmitterConfig, registry: Option) -> Handler { - mk_handler(box EmitterWriter::stderr(color_config, registry)) + mk_handler(box EmitterWriter::stderr(cfg, registry)) } pub fn mk_handler(e: Box) -> Handler { @@ -320,7 +364,8 @@ fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, pub struct EmitterWriter { dst: Destination, - registry: Option + registry: Option, + cfg: EmitterConfig, } enum Destination { @@ -329,11 +374,11 @@ enum Destination { } impl EmitterWriter { - pub fn stderr(color_config: ColorConfig, + pub fn stderr(cfg: EmitterConfig, registry: Option) -> EmitterWriter { let stderr = io::stderr(); - let use_color = match color_config { + let use_color = match cfg.color { ColorConfig::Always => true, ColorConfig::Never => false, ColorConfig::Auto => stderr.get_ref().isatty() @@ -344,15 +389,15 @@ impl EmitterWriter { Some(t) => Terminal(t), None => Raw(box stderr), }; - EmitterWriter { dst: dst, registry: registry } + EmitterWriter { dst: dst, registry: registry, cfg: cfg } } else { - EmitterWriter { dst: Raw(box stderr), registry: registry } + EmitterWriter { dst: Raw(box stderr), registry: registry, cfg: cfg } } } pub fn new(dst: Box, registry: Option) -> EmitterWriter { - EmitterWriter { dst: Raw(dst), registry: registry } + EmitterWriter { dst: Raw(dst), registry: registry, cfg: Default::default() } } } @@ -497,14 +542,20 @@ fn highlight_lines(err: &mut EmitterWriter, } try!(write!(&mut err.dst, "{}", s)); - let mut s = String::from_str("^"); + let fmt = err.cfg.span_format(); + let mut s = String::new(); + let hi = cm.lookup_char_pos(sp.hi); - if hi.col != lo.col { - // the ^ already takes up one space - let num_squigglies = hi.col.to_uint() - lo.col.to_uint() - 1u; + let len = hi.col.to_uint() - lo.col.to_uint(); + if len <= 1 { + s.push(fmt.single); + } else { + s.push(fmt.begin); + let num_squigglies = len - 2u; for _ in range(0, num_squigglies) { - s.push('~'); + s.push(fmt.middle); } + s.push(fmt.end); } try!(print_maybe_styled(err, &format!("{}\n", s)[], @@ -555,7 +606,7 @@ fn custom_highlight_lines(w: &mut EmitterWriter, for _ in range(0, skip) { s.push(' '); } - s.push('^'); + s.push(w.cfg.span_format().single); s.push('\n'); print_maybe_styled(w, &s[], diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7dd7035f769e1..222f3ebd324d4 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast; use codemap::{Span, CodeMap, FileMap}; -use diagnostic::{SpanHandler, mk_span_handler, default_handler, ColorConfig}; +use diagnostic::{SpanHandler, mk_span_handler, default_handler}; use parse::attr::ParserAttr; use parse::parser::Parser; use ptr::P; @@ -21,6 +21,7 @@ use std::cell::{Cell, RefCell}; use std::io::File; use std::rc::Rc; use std::num::Int; +use std::default::Default; use std::str; use std::iter; @@ -45,7 +46,7 @@ pub struct ParseSess { pub fn new_parse_sess() -> ParseSess { ParseSess { - span_diagnostic: mk_span_handler(default_handler(ColorConfig::Auto, None), + span_diagnostic: mk_span_handler(default_handler(Default::default(), None), CodeMap::new()), included_mod_stack: RefCell::new(Vec::new()), node_id: Cell::new(1), diff --git a/src/test/compile-fail/drawing-spans-one-char.rs b/src/test/compile-fail/drawing-spans-one-char.rs new file mode 100644 index 0000000000000..3df1840d18ec5 --- /dev/null +++ b/src/test/compile-fail/drawing-spans-one-char.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--drawing +// error-pattern: ▲ + +#![deny(warnings)] + +fn main() { + let x = 3; +} diff --git a/src/test/compile-fail/drawing-spans.rs b/src/test/compile-fail/drawing-spans.rs new file mode 100644 index 0000000000000..8b343cf092336 --- /dev/null +++ b/src/test/compile-fail/drawing-spans.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:--drawing +// error-pattern: ┗━━━━┛ + +#![deny(warnings)] + +fn main() { + let foobar = 3; +}