about summary refs log tree commit diff
path: root/src/librustc_errors
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-01-11 13:55:41 -0800
committerEsteban Küber <esteban@kuber.com.ar>2017-01-17 14:28:53 -0800
commitfc774e629fd805ef46566894da482ed8be680303 (patch)
tree04e098b9d07adac374ea2cfe041c64df788d1430 /src/librustc_errors
parentbd8e9b0c828bce489eb948853a6cf86b69b26799 (diff)
downloadrust-fc774e629fd805ef46566894da482ed8be680303.tar.gz
rust-fc774e629fd805ef46566894da482ed8be680303.zip
Teach Diagnostics to highlight text
Diffstat (limited to 'src/librustc_errors')
-rw-r--r--src/librustc_errors/diagnostic.rs56
-rw-r--r--src/librustc_errors/emitter.rs101
-rw-r--r--src/librustc_errors/snippet.rs1
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,
 }