From 73ee491484ed7f3ab2498769ff16aba4750e3835 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Mon, 19 Jan 2015 12:57:52 -0800 Subject: [PATCH] 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/librustc/lint/context.rs | 6 +- src/librustc/session/config.rs | 59 +++++++------- src/librustc/session/mod.rs | 10 +-- src/librustc/session/search_paths.rs | 4 +- src/librustc_back/target/mod.rs | 2 +- src/librustc_driver/lib.rs | 22 +++--- src/librustdoc/core.rs | 3 +- src/librustdoc/test.rs | 3 +- src/libsyntax/diagnostic.rs | 78 ++++++++++++++++--- src/libsyntax/parse/mod.rs | 5 +- .../compile-fail/drawing-spans-one-char.rs | 18 +++++ src/test/compile-fail/drawing-spans.rs | 18 +++++ 13 files changed, 167 insertions(+), 64 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 56e3fe0515eb9..2d2e53cd50ba0 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -139,6 +139,9 @@ always colorize output; .B never never colorize output. .RE +.TP +\fB\-\-drawing\fR +Use drawing characters in diagnostic output .SH CODEGEN OPTIONS diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index 44341562b98bd..9f2eeeea016a0 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -36,6 +36,7 @@ use util::nodemap::FnvHashMap; use std::cell::RefCell; use std::cmp; +use std::default; use std::mem; use syntax::ast_util::{self, IdVisitingOperation}; use syntax::attr::{self, AttrMetaMethods}; @@ -46,7 +47,6 @@ use rustc_front::hir; use rustc_front::util; use rustc_front::visit as hir_visit; use syntax::visit as ast_visit; -use syntax::diagnostic; /// Information about the registered lints. /// @@ -166,7 +166,7 @@ impl LintStore { match (sess, from_plugin) { // We load builtin lints first, so a duplicate is a compiler bug. // Use early_error when handling -W help with no crate. - (None, _) => early_error(diagnostic::ColorConfig::Auto, &msg[..]), + (None, _) => early_error(default::Default::default(), &msg[..]), (Some(sess), false) => sess.bug(&msg[..]), // A duplicate name from a plugin is a user error. @@ -190,7 +190,7 @@ impl LintStore { match (sess, from_plugin) { // We load builtin lints first, so a duplicate is a compiler bug. // Use early_error when handling -W help with no crate. - (None, _) => early_error(diagnostic::ColorConfig::Auto, &msg[..]), + (None, _) => early_error(default::Default::default(), &msg[..]), (Some(sess), false) => sess.bug(&msg[..]), // A duplicate name from a plugin is a user error. diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 91d56e2c465b1..4d815a0a3b445 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -27,7 +27,8 @@ use metadata::cstore; use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; use syntax::attr::AttrMetaMethods; -use syntax::diagnostic::{ColorConfig, SpanHandler}; +use syntax::diagnostic; +use syntax::diagnostic::{ColorConfig, EmitterConfig, SpanHandler}; use syntax::parse; use syntax::parse::token::InternedString; use syntax::feature_gate::UnstableFeatures; @@ -37,6 +38,7 @@ use std::collections::HashMap; use std::env; use std::fmt; use std::path::PathBuf; +use std::default; use llvm; @@ -106,7 +108,7 @@ pub struct Options { pub debugging_opts: DebuggingOptions, 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, @@ -216,7 +218,7 @@ pub fn basic_options() -> Options { debugging_opts: basic_debugging_options(), prints: Vec::new(), cg: basic_codegen_options(), - color: ColorConfig::Auto, + emit_cfg: default::Default::default(), show_span: None, externs: HashMap::new(), crate_name: None, @@ -284,7 +286,7 @@ macro_rules! options { $struct_name { $($opt: $init),* } } - pub fn $buildfn(matches: &getopts::Matches, color: ColorConfig) -> $struct_name + pub fn $buildfn(matches: &getopts::Matches, cfg: EmitterConfig) -> $struct_name { let mut op = $defaultfn(); for option in matches.opt_strs($prefix) { @@ -298,17 +300,17 @@ macro_rules! options { if !setter(&mut op, value) { match (value, opt_type_desc) { (Some(..), None) => { - early_error(color, &format!("{} option `{}` takes no \ + early_error(cfg, &format!("{} option `{}` takes no \ value", $outputname, key)) } (None, Some(type_desc)) => { - early_error(color, &format!("{0} option `{1}` requires \ + early_error(cfg, &format!("{0} option `{1}` requires \ {2} ({3} {1}=)", $outputname, key, type_desc, $prefix)) } (Some(value), Some(type_desc)) => { - early_error(color, &format!("incorrect value `{}` for {} \ + early_error(cfg, &format!("incorrect value `{}` for {} \ option `{}` - {} was expected", value, $outputname, key, type_desc)) @@ -320,7 +322,7 @@ macro_rules! options { break; } if !found { - early_error(color, &format!("unknown {} option: `{}`", + early_error(cfg, &format!("unknown {} option: `{}`", $outputname, key)); } } @@ -822,6 +824,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"), opt::flagopt_u("", "pretty", "Pretty-print the input instead of compiling; @@ -853,7 +856,8 @@ pub fn parse_cfgspecs(cfgspecs: Vec ) -> ast::CrateConfig { } pub fn build_session_options(matches: &getopts::Matches) -> Options { - let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) { + let mut emit_cfg: diagnostic::EmitterConfig = default::Default::default(); + emit_cfg.color = match matches.opt_str("color").as_ref().map(|s| &s[..]) { Some("auto") => ColorConfig::Auto, Some("always") => ColorConfig::Always, Some("never") => ColorConfig::Never, @@ -861,16 +865,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { None => ColorConfig::Auto, Some(arg) => { - early_error(ColorConfig::Auto, + early_error(emit_cfg, &format!("argument for --color must be auto, always \ or never (instead was `{}`)", arg)) } }; + if matches.opt_present("drawing") { + emit_cfg.drawing = true; + } let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) - .unwrap_or_else(|e| early_error(color, &e[..])); + .unwrap_or_else(|e| early_error(emit_cfg, &e[..])); let mut lint_opts = vec!(); let mut describe_lints = false; @@ -887,11 +894,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap).unwrap_or_else(|| { - early_error(color, &format!("unknown lint level: `{}`", cap)) + early_error(emit_cfg, &format!("unknown lint level: `{}`", cap)) }) }); - let debugging_opts = build_debugging_options(matches, color); + let debugging_opts = build_debugging_options(matches, emit_cfg); let parse_only = debugging_opts.parse_only; let no_trans = debugging_opts.no_trans; @@ -916,7 +923,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { "link" => OutputType::Exe, "dep-info" => OutputType::DepInfo, part => { - early_error(color, &format!("unknown emission type: `{}`", + early_error(emit_cfg, &format!("unknown emission type: `{}`", part)) } }; @@ -929,7 +936,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { output_types.insert(OutputType::Exe, None); } - let cg = build_codegen_options(matches, color); + let cg = build_codegen_options(matches, emit_cfg); let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); let target = matches.opt_str("target").unwrap_or( @@ -937,7 +944,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let opt_level = { if matches.opt_present("O") { if cg.opt_level.is_some() { - early_error(color, "-O and -C opt-level both provided"); + early_error(emit_cfg, "-O and -C opt-level both provided"); } Default } else { @@ -948,7 +955,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { Some(2) => Default, Some(3) => Aggressive, Some(arg) => { - early_error(color, &format!("optimization level needs to be \ + early_error(emit_cfg, &format!("optimization level needs to be \ between 0-3 (instead was `{}`)", arg)); } @@ -959,7 +966,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let gc = debugging_opts.gc; let debuginfo = if matches.opt_present("g") { if cg.debuginfo.is_some() { - early_error(color, "-g and -C debuginfo both provided"); + early_error(emit_cfg, "-g and -C debuginfo both provided"); } FullDebugInfo } else { @@ -968,7 +975,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { Some(1) => LimitedDebugInfo, Some(2) => FullDebugInfo, Some(arg) => { - early_error(color, &format!("debug info level needs to be between \ + early_error(emit_cfg, &format!("debug info level needs to be between \ 0-2 (instead was `{}`)", arg)); } @@ -977,7 +984,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut search_paths = SearchPaths::new(); for s in &matches.opt_strs("L") { - search_paths.add_path(&s[..], color); + search_paths.add_path(&s[..], emit_cfg); } let libs = matches.opt_strs("l").into_iter().map(|s| { @@ -989,7 +996,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { (Some(name), "framework") => (name, cstore::NativeFramework), (Some(name), "static") => (name, cstore::NativeStatic), (_, s) => { - early_error(color, &format!("unknown library kind `{}`, expected \ + early_error(emit_cfg, &format!("unknown library kind `{}`, expected \ one of dylib, framework, or static", s)); } @@ -1006,13 +1013,13 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { "file-names" => PrintRequest::FileNames, "sysroot" => PrintRequest::Sysroot, req => { - early_error(color, &format!("unknown print request `{}`", req)) + early_error(emit_cfg, &format!("unknown print request `{}`", req)) } } }).collect::>(); if !cg.remark.is_empty() && debuginfo == NoDebugInfo { - early_warn(color, "-C remark will not show source locations without \ + early_warn(emit_cfg, "-C remark will not show source locations without \ --debuginfo"); } @@ -1021,11 +1028,11 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut parts = arg.splitn(2, '='); let name = match parts.next() { Some(s) => s, - None => early_error(color, "--extern value must not be empty"), + None => early_error(emit_cfg, "--extern value must not be empty"), }; let location = match parts.next() { Some(s) => s, - None => early_error(color, "--extern value must be of the format `foo=bar`"), + None => early_error(emit_cfg, "--extern value must be of the format `foo=bar`"), }; externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string()); @@ -1055,7 +1062,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { debugging_opts: debugging_opts, 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 9d1674b74d1fc..0bf2e4d3bd890 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -394,7 +394,7 @@ pub fn build_session(sopts: config::Options, let codemap = codemap::CodeMap::new(); let diagnostic_handler = - diagnostic::Handler::new(sopts.color, Some(registry), can_print_warnings); + diagnostic::Handler::new(sopts.emit_cfg, Some(registry), can_print_warnings); let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap); @@ -473,13 +473,13 @@ pub fn expect(sess: &Session, opt: Option, msg: M) -> T where diagnostic::expect(sess.diagnostic(), opt, msg) } -pub fn early_error(color: diagnostic::ColorConfig, msg: &str) -> ! { - let mut emitter = diagnostic::EmitterWriter::stderr(color, None); +pub fn early_error(cfg: diagnostic::EmitterConfig, msg: &str) -> ! { + let mut emitter = diagnostic::EmitterWriter::stderr(cfg, None); emitter.emit(None, msg, None, diagnostic::Fatal); panic!(diagnostic::FatalError); } -pub fn early_warn(color: diagnostic::ColorConfig, msg: &str) { - let mut emitter = diagnostic::EmitterWriter::stderr(color, None); +pub fn early_warn(cfg: diagnostic::EmitterConfig, msg: &str) { + let mut emitter = diagnostic::EmitterWriter::stderr(cfg, None); emitter.emit(None, msg, None, diagnostic::Warning); } diff --git a/src/librustc/session/search_paths.rs b/src/librustc/session/search_paths.rs index caf776dad85e0..1826ad341a91e 100644 --- a/src/librustc/session/search_paths.rs +++ b/src/librustc/session/search_paths.rs @@ -38,7 +38,7 @@ impl SearchPaths { SearchPaths { paths: Vec::new() } } - pub fn add_path(&mut self, path: &str, color: diagnostic::ColorConfig) { + pub fn add_path(&mut self, path: &str, cfg: diagnostic::EmitterConfig) { let (kind, path) = if path.starts_with("native=") { (PathKind::Native, &path["native=".len()..]) } else if path.starts_with("crate=") { @@ -53,7 +53,7 @@ impl SearchPaths { (PathKind::All, path) }; if path.is_empty() { - early_error(color, "empty search path given via `-L`"); + early_error(cfg, "empty search path given via `-L`"); } self.paths.push((kind, PathBuf::from(path))); } diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 8d4ee4ce12bf9..51cf3ec0c0f46 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -250,7 +250,7 @@ impl Target { // this is 1. ugly, 2. error prone. - let handler = diagnostic::Handler::new(diagnostic::ColorConfig::Auto, None, true); + let handler = diagnostic::Handler::new(Default::default(), None, true); 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 5d9fab594ac57..a642e00c302de 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -123,7 +123,7 @@ pub fn run_compiler<'a>(args: &[String], let descriptions = diagnostics_registry(); - do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.color)); + do_or_return!(callbacks.early_callback(&matches, &descriptions, sopts.emit_cfg)); let (odir, ofile) = make_output(&matches); let (input, input_file_path) = match make_input(&matches.free) { @@ -208,7 +208,7 @@ pub trait CompilerCalls<'a> { fn early_callback(&mut self, _: &getopts::Matches, _: &diagnostics::registry::Registry, - _: diagnostic::ColorConfig) + _: diagnostic::EmitterConfig) -> Compilation { Compilation::Continue } @@ -281,7 +281,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn early_callback(&mut self, matches: &getopts::Matches, descriptions: &diagnostics::registry::Registry, - color: diagnostic::ColorConfig) + cfg: diagnostic::EmitterConfig) -> Compilation { match matches.opt_str("explain") { Some(ref code) => { @@ -291,7 +291,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { print!("{}", &description[1..]); } None => { - early_error(color, &format!("no extended information for {}", code)); + early_error(cfg, &format!("no extended information for {}", code)); } } return Compilation::Stop; @@ -323,10 +323,10 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { if should_stop == Compilation::Stop { return None; } - early_error(sopts.color, "no input filename given"); + early_error(sopts.emit_cfg, "no input filename given"); } 1 => panic!("make_input should have provided valid inputs"), - _ => early_error(sopts.color, "multiple input filenames provided") + _ => early_error(sopts.emit_cfg, "multiple input filenames provided") } None @@ -419,7 +419,7 @@ impl RustcDefaultCalls { println!("{}", String::from_utf8(v).unwrap()); } &Input::Str(_) => { - early_error(sess.opts.color, "cannot list metadata for stdin"); + early_error(sess.opts.emit_cfg, "cannot list metadata for stdin"); } } return Compilation::Stop; @@ -446,7 +446,7 @@ impl RustcDefaultCalls { PrintRequest::CrateName => { let input = match input { Some(input) => input, - None => early_error(sess.opts.color, "no input file provided"), + None => early_error(sess.opts.emit_cfg, "no input file provided"), }; let attrs = attrs.as_ref().unwrap(); let t_outputs = driver::build_output_filenames(input, @@ -706,7 +706,7 @@ pub fn handle_options(mut args: Vec) -> Option { &opt.opt_group.short_name }; if m.opt_present(opt_name) { - early_error(diagnostic::ColorConfig::Auto, + early_error(Default::default(), &format!("use of unstable option '{}' \ requires -Z unstable-options", opt_name)); @@ -715,7 +715,7 @@ pub fn handle_options(mut args: Vec) -> Option { } m } - Err(f) => early_error(diagnostic::ColorConfig::Auto, &f.to_string()) + Err(f) => early_error(Default::default(), &f.to_string()) } } @@ -821,7 +821,7 @@ pub fn monitor(f: F) { // Thread panicked without emitting a fatal diagnostic if !value.is::() { let mut emitter = diagnostic::EmitterWriter::stderr( - diagnostic::ColorConfig::Auto, None); + Default::default(), None); // a .span_bug or .bug call has already printed what // it wants to print. diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index c84a7e7c560dd..a4caeb897eb42 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -26,6 +26,7 @@ use syntax::feature_gate::UnstableFeatures; use std::cell::{RefCell, Cell}; use std::collections::{HashMap, HashSet}; +use std::default::Default; use visit_ast::RustdocVisitor; use clean; @@ -114,7 +115,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, }; let codemap = codemap::CodeMap::new(); - let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true); + let diagnostic_handler = diagnostic::Handler::new(Default::default(), None, true); let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 37669d5a9b145..f588d76bea01b 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -19,6 +19,7 @@ use std::path::PathBuf; use std::process::Command; use std::str; use std::sync::{Arc, Mutex}; +use std::default::Default; use testing; use rustc_lint; @@ -67,7 +68,7 @@ pub fn run(input: &str, }; let codemap = CodeMap::new(); - let diagnostic_handler = diagnostic::Handler::new(diagnostic::Auto, None, true); + let diagnostic_handler = diagnostic::Handler::new(Default::default(), None, true); let span_diagnostic_handler = diagnostic::SpanHandler::new(diagnostic_handler, codemap); diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 1a8b316976912..50c82e307ea33 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -16,6 +16,7 @@ use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; use diagnostics; use std::cell::{RefCell, Cell}; +use std::default::Default; use std::{cmp, error, fmt}; use std::io::prelude::*; use std::io; @@ -69,6 +70,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); @@ -192,10 +236,10 @@ pub struct Handler { } impl Handler { - pub fn new(color_config: ColorConfig, + pub fn new(emitter_config: EmitterConfig, registry: Option, can_emit_warnings: bool) -> Handler { - let emitter = Box::new(EmitterWriter::stderr(color_config, registry)); + let emitter = Box::new(EmitterWriter::stderr(emitter_config, registry)); Handler::with_emitter(can_emit_warnings, emitter) } pub fn with_emitter(can_emit_warnings: bool, e: Box) -> Handler { @@ -313,7 +357,8 @@ impl Level { pub struct EmitterWriter { dst: Destination, - registry: Option + registry: Option, + cfg: EmitterConfig, } enum Destination { @@ -336,11 +381,11 @@ macro_rules! println_maybe_styled { } 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_isatty() @@ -351,15 +396,15 @@ impl EmitterWriter { Some(t) => Terminal(t), None => Raw(Box::new(stderr)), }; - EmitterWriter { dst: dst, registry: registry } + EmitterWriter { dst: dst, registry: registry, cfg: cfg } } else { - EmitterWriter { dst: Raw(Box::new(stderr)), registry: registry } + EmitterWriter { dst: Raw(Box::new(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() } } fn print_maybe_styled(&mut self, @@ -618,14 +663,16 @@ impl EmitterWriter { } try!(write!(&mut self.dst, "{}", s)); - let mut s = String::from("^"); + let mut s = String::new(); + let fmt = self.cfg.span_format(); let count = match lastc { // Most terminals have a tab stop every eight columns by default '\t' => 8 - col%8, _ => 1, }; col += count; - s.extend(::std::iter::repeat('~').take(count)); + s.push(fmt.begin); + s.extend(::std::iter::repeat(fmt.middle).take(count)); let hi = cm.lookup_char_pos(sp.hi); if hi.col != lo.col { @@ -636,7 +683,7 @@ impl EmitterWriter { _ => 1, }; col += count; - s.extend(::std::iter::repeat('~').take(count)); + s.extend(::std::iter::repeat(fmt.middle).take(count)); } } @@ -645,6 +692,13 @@ impl EmitterWriter { s.pop(); } + s.pop(); + if s.is_empty() { + s.push(fmt.single); + } else { + s.push(fmt.end); + } + try!(println_maybe_styled!(self, term::attr::ForegroundColor(lvl.color()), "{}", s)); } @@ -717,7 +771,7 @@ impl EmitterWriter { } } } - s.push('^'); + s.push(self.cfg.span_format().single); println_maybe_styled!(self, term::attr::ForegroundColor(lvl.color()), "{}", s) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index a907683cf8d8d..159c3d6d62a78 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -12,7 +12,7 @@ use ast; use codemap::{self, Span, CodeMap, FileMap}; -use diagnostic::{SpanHandler, Handler, ColorConfig, FatalError}; +use diagnostic::{SpanHandler, Handler, FatalError}; use parse::attr::ParserAttr; use parse::parser::Parser; use parse::token::InternedString; @@ -24,6 +24,7 @@ use std::io::Read; use std::iter; use std::path::{Path, PathBuf}; use std::rc::Rc; +use std::default::Default; use std::str; pub type PResult = Result; @@ -48,7 +49,7 @@ pub struct ParseSess { impl ParseSess { pub fn new() -> ParseSess { - let handler = SpanHandler::new(Handler::new(ColorConfig::Auto, None, true), CodeMap::new()); + let handler = SpanHandler::new(Handler::new(Default::default(), None, true), CodeMap::new()); ParseSess::with_span_handler(handler) } 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; +}