diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2017-01-11 13:55:41 -0800 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2017-01-17 14:28:53 -0800 |
| commit | fc774e629fd805ef46566894da482ed8be680303 (patch) | |
| tree | 04e098b9d07adac374ea2cfe041c64df788d1430 /src/librustc_errors | |
| parent | bd8e9b0c828bce489eb948853a6cf86b69b26799 (diff) | |
| download | rust-fc774e629fd805ef46566894da482ed8be680303.tar.gz rust-fc774e629fd805ef46566894da482ed8be680303.zip | |
Teach Diagnostics to highlight text
Diffstat (limited to 'src/librustc_errors')
| -rw-r--r-- | src/librustc_errors/diagnostic.rs | 56 | ||||
| -rw-r--r-- | src/librustc_errors/emitter.rs | 101 | ||||
| -rw-r--r-- | src/librustc_errors/snippet.rs | 1 |
3 files changed, 125 insertions, 33 deletions
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 730ca8f9e2e..ac39af20189 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -14,12 +14,13 @@ use RenderSpan; use RenderSpan::Suggestion; use std::fmt; use syntax_pos::{MultiSpan, Span}; +use snippet::Style; #[must_use] #[derive(Clone, Debug, PartialEq)] pub struct Diagnostic { pub level: Level, - pub message: String, + pub message: Vec<(String, Style)>, pub code: Option<String>, pub span: MultiSpan, pub children: Vec<SubDiagnostic>, @@ -29,7 +30,7 @@ pub struct Diagnostic { #[derive(Clone, Debug, PartialEq)] pub struct SubDiagnostic { pub level: Level, - pub message: String, + pub message: Vec<(String, Style)>, pub span: MultiSpan, pub render_span: Option<RenderSpan>, } @@ -42,7 +43,7 @@ impl Diagnostic { pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self { Diagnostic { level: level, - message: message.to_owned(), + message: vec![(message.to_owned(), Style::NoStyle)], code: code, span: MultiSpan::new(), children: vec![], @@ -96,8 +97,14 @@ impl Diagnostic { -> &mut Self { // For now, just attach these as notes - self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); - self.note(&format!(" found {} `{}`{}", label, found, found_extra)); + self.highlighted_note(vec![ + (format!("expected {} `", label), Style::NoStyle), + (format!("{}", expected), Style::Highlight), + (format!("`{}\n", expected_extra), Style::NoStyle), + (format!(" found {} `", label), Style::NoStyle), + (format!("{}", found), Style::Highlight), + (format!("`{}", found_extra), Style::NoStyle), + ]); self } @@ -106,6 +113,11 @@ impl Diagnostic { self } + pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self { + self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None); + self + } + pub fn span_note<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) @@ -168,7 +180,11 @@ impl Diagnostic { self } - pub fn message(&self) -> &str { + pub fn message(&self) -> String { + self.message.iter().map(|i| i.0.to_owned()).collect::<String>() + } + + pub fn styled_message(&self) -> &Vec<(String, Style)> { &self.message } @@ -193,10 +209,36 @@ impl Diagnostic { render_span: Option<RenderSpan>) { let sub = SubDiagnostic { level: level, - message: message.to_owned(), + message: vec![(message.to_owned(), Style::NoStyle)], span: span, render_span: render_span, }; self.children.push(sub); } + + /// Convenience function for internal use, clients should use one of the + /// public methods above. + fn sub_with_highlights(&mut self, + level: Level, + message: Vec<(String, Style)>, + span: MultiSpan, + render_span: Option<RenderSpan>) { + let sub = SubDiagnostic { + level: level, + message: message, + span: span, + render_span: render_span, + }; + self.children.push(sub); + } +} + +impl SubDiagnostic { + pub fn message(&self) -> String { + self.message.iter().map(|i| i.0.to_owned()).collect::<String>() + } + + pub fn styled_message(&self) -> &Vec<(String, Style)> { + &self.message + } } diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 77c6c368364..5d758d322c7 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -33,7 +33,11 @@ impl Emitter for EmitterWriter { let mut primary_span = db.span.clone(); let mut children = db.children.clone(); self.fix_multispans_in_std_macros(&mut primary_span, &mut children); - self.emit_messages_default(&db.level, &db.message, &db.code, &primary_span, &children); + self.emit_messages_default(&db.level, + &db.styled_message(), + &db.code, + &primary_span, + &children); } } @@ -695,8 +699,8 @@ impl EmitterWriter { if spans_updated { children.push(SubDiagnostic { level: Level::Note, - message: "this error originates in a macro outside of the current crate" - .to_string(), + message: vec![("this error originates in a macro outside of the current crate" + .to_string(), Style::NoStyle)], span: MultiSpan::new(), render_span: None, }); @@ -704,8 +708,14 @@ impl EmitterWriter { } /// Add a left margin to every line but the first, given a padding length and the label being - /// displayed. - fn msg_with_padding(&self, msg: &str, padding: usize, label: &str) -> String { + /// displayed, keeping the provided highlighting. + fn msg_to_buffer(&self, + buffer: &mut StyledBuffer, + msg: &Vec<(String, Style)>, + padding: usize, + label: &str, + override_style: Option<Style>) { + // The extra 5 ` ` is padding that's always needed to align to the `note: `: // // error: message @@ -726,20 +736,56 @@ impl EmitterWriter { .map(|_| " ") .collect::<String>(); - msg.split('\n').enumerate().fold("".to_owned(), |mut acc, x| { - if x.0 != 0 { - acc.push_str("\n"); - // Align every line with first one. - acc.push_str(&padding); + /// Return wether `style`, or the override if present and the style is `NoStyle`. + fn style_or_override(style: Style, override_style: Option<Style>) -> Style { + if let Some(o) = override_style { + if style == Style::NoStyle { + return o; + } + } + style + } + + let mut line_number = 0; + + // Provided the following diagnostic message: + // + // let msg = vec![ + // (" + // ("highlighted multiline\nstring to\nsee how it ", Style::NoStyle), + // ("looks", Style::Highlight), + // ("with\nvery ", Style::NoStyle), + // ("weird", Style::Highlight), + // (" formats\n", Style::NoStyle), + // ("see?", Style::Highlight), + // ]; + // + // the expected output on a note is (* surround the highlighted text) + // + // = note: highlighted multiline + // string to + // see how it *looks* with + // very *weird* formats + // see? + for &(ref text, ref style) in msg.iter() { + let lines = text.split('\n').collect::<Vec<_>>(); + if lines.len() > 1 { + for (i, line) in lines.iter().enumerate() { + if i != 0 { + line_number += 1; + buffer.append(line_number, &padding, Style::NoStyle); + } + buffer.append(line_number, line, style_or_override(*style, override_style)); + } + } else { + buffer.append(line_number, text, style_or_override(*style, override_style)); } - acc.push_str(&x.1); - acc - }) + } } fn emit_message_default(&mut self, msp: &MultiSpan, - msg: &str, + msg: &Vec<(String, Style)>, code: &Option<String>, level: &Level, max_line_num_len: usize, @@ -755,9 +801,7 @@ impl EmitterWriter { draw_note_separator(&mut buffer, 0, max_line_num_len + 1); buffer.append(0, &level.to_string(), Style::HeaderMsg); buffer.append(0, ": ", Style::NoStyle); - - let message = self.msg_with_padding(msg, max_line_num_len, "note"); - buffer.append(0, &message, Style::NoStyle); + self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { buffer.append(0, &level.to_string(), Style::Level(level.clone())); match code { @@ -769,7 +813,9 @@ impl EmitterWriter { _ => {} } buffer.append(0, ": ", Style::HeaderMsg); - buffer.append(0, msg, Style::HeaderMsg); + for &(ref text, _) in msg.iter() { + buffer.append(0, text, Style::HeaderMsg); + } } // Preprocess all the annotations so that they are grouped by file and by line number @@ -879,7 +925,7 @@ impl EmitterWriter { fn emit_suggestion_default(&mut self, suggestion: &CodeSuggestion, level: &Level, - msg: &str, + msg: &Vec<(String, Style)>, max_line_num_len: usize) -> io::Result<()> { use std::borrow::Borrow; @@ -890,9 +936,11 @@ impl EmitterWriter { buffer.append(0, &level.to_string(), Style::Level(level.clone())); buffer.append(0, ": ", Style::HeaderMsg); - - let message = self.msg_with_padding(msg, max_line_num_len, "suggestion"); - buffer.append(0, &message, Style::HeaderMsg); + self.msg_to_buffer(&mut buffer, + msg, + max_line_num_len, + "suggestion", + Some(Style::HeaderMsg)); let lines = cm.span_to_lines(primary_span).unwrap(); @@ -921,7 +969,7 @@ impl EmitterWriter { } fn emit_messages_default(&mut self, level: &Level, - message: &String, + message: &Vec<(String, Style)>, code: &Option<String>, span: &MultiSpan, children: &Vec<SubDiagnostic>) { @@ -942,7 +990,7 @@ impl EmitterWriter { match child.render_span { Some(FullSpan(ref msp)) => { match self.emit_message_default(msp, - &child.message, + &child.styled_message(), &None, &child.level, max_line_num_len, @@ -954,7 +1002,7 @@ impl EmitterWriter { Some(Suggestion(ref cs)) => { match self.emit_suggestion_default(cs, &child.level, - &child.message, + &child.styled_message(), max_line_num_len) { Err(e) => panic!("failed to emit error: {}", e), _ => () @@ -962,7 +1010,7 @@ impl EmitterWriter { }, None => { match self.emit_message_default(&child.span, - &child.message, + &child.styled_message(), &None, &child.level, max_line_num_len, @@ -1197,6 +1245,7 @@ impl Destination { self.start_attr(term::Attr::Bold)?; self.start_attr(term::Attr::ForegroundColor(l.color()))?; } + Style::Highlight => self.start_attr(term::Attr::Bold)?, } Ok(()) } diff --git a/src/librustc_errors/snippet.rs b/src/librustc_errors/snippet.rs index b8c1726443d..18e7b324f08 100644 --- a/src/librustc_errors/snippet.rs +++ b/src/librustc_errors/snippet.rs @@ -185,4 +185,5 @@ pub enum Style { NoStyle, ErrorCode, Level(Level), + Highlight, } |
