diff options
Diffstat (limited to 'compiler/rustc_errors/src/emitter.rs')
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index e16ff974122..3104bc185e7 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -214,7 +214,7 @@ pub trait Emitter { /// Formats the substitutions of the primary_span /// - /// The are a lot of conditions to this method, but in short: + /// There are a lot of conditions to this method, but in short: /// /// * If the current `Diagnostic` has only one visible `CodeSuggestion`, /// we format the `help` suggestion depending on the content of the @@ -730,13 +730,15 @@ impl EmitterWriter { } let source_string = match file.get_line(line.line_index - 1) { - Some(s) => replace_tabs(&*s), + Some(s) => normalize_whitespace(&*s), None => return Vec::new(), }; let line_offset = buffer.num_lines(); - let left = margin.left(source_string.len()); // Left trim + // Left trim + let left = margin.left(source_string.len()); + // Account for unicode characters of width !=0 that were removed. let left = source_string .chars() @@ -1266,22 +1268,37 @@ impl EmitterWriter { } self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { + let mut label_width = 0; // The failure note level itself does not provide any useful diagnostic information if *level != Level::FailureNote { buffer.append(0, level.to_str(), Style::Level(*level)); + label_width += level.to_str().len(); } // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { buffer.append(0, "[", Style::Level(*level)); buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); + label_width += 2 + code.len(); } let header_style = if is_secondary { Style::HeaderMsg } else { Style::MainHeaderMsg }; if *level != Level::FailureNote { buffer.append(0, ": ", header_style); + label_width += 2; } for &(ref text, _) in msg.iter() { - buffer.append(0, &replace_tabs(text), header_style); + // Account for newlines to align output to its label. + for (line, text) in normalize_whitespace(text).lines().enumerate() { + buffer.append( + 0 + line, + &format!( + "{}{}", + if line == 0 { String::new() } else { " ".repeat(label_width) }, + text + ), + header_style, + ); + } } } @@ -1535,7 +1552,7 @@ impl EmitterWriter { self.draw_line( &mut buffer, - &replace_tabs(&unannotated_line), + &normalize_whitespace(&unannotated_line), annotated_file.lines[line_idx + 1].line_index - 1, last_buffer_line_num, width_offset, @@ -1608,18 +1625,27 @@ impl EmitterWriter { suggestions.iter().take(MAX_SUGGESTIONS) { notice_capitalization |= only_capitalization; - // Only show underline if the suggestion spans a single line and doesn't cover the - // entirety of the code output. If you have multiple replacements in the same line - // of code, show the underline. - let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim()) - && complete.lines().count() == 1; let has_deletion = parts.iter().any(|p| p.is_deletion()); let is_multiline = complete.lines().count() > 1; - let show_diff = has_deletion && !is_multiline; + enum DisplaySuggestion { + Underline, + Diff, + None, + } + + let show_code_change = if has_deletion && !is_multiline { + DisplaySuggestion::Diff + } else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim()) + && !is_multiline + { + DisplaySuggestion::Underline + } else { + DisplaySuggestion::None + }; - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { row_num += 1; } @@ -1642,7 +1668,7 @@ impl EmitterWriter { &self.maybe_anonymized(line_start + line_pos), Style::LineNumber, ); - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { // Add the line number for both addition and removal to drive the point home. // // N - fn foo<A: T>(bar: A) { @@ -1657,7 +1683,7 @@ impl EmitterWriter { buffer.puts( row_num - 1, max_line_num_len + 3, - &replace_tabs( + &normalize_whitespace( &*file_lines .file .get_line(file_lines.lines[line_pos].line_index) @@ -1683,7 +1709,7 @@ impl EmitterWriter { } // print the suggestion - buffer.append(row_num, &replace_tabs(line), Style::NoStyle); + buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle); // Colorize addition/replacements with green. for &SubstitutionHighlight { start, end } in highlight_parts { @@ -1712,7 +1738,7 @@ impl EmitterWriter { let mut offsets: Vec<(usize, isize)> = Vec::new(); // Only show an underline in the suggestions if the suggestion is not the // entirety of the code being shown and the displayed code is not multiline. - if show_underline { + if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change { draw_col_separator(&mut buffer, row_num, max_line_num_len + 1); for part in parts { let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display; @@ -1740,7 +1766,7 @@ impl EmitterWriter { assert!(underline_start >= 0 && underline_end >= 0); let padding: usize = max_line_num_len + 3; for p in underline_start..underline_end { - if !show_diff { + if let DisplaySuggestion::Underline = show_code_change { // If this is a replacement, underline with `^`, if this is an addition // underline with `+`. buffer.putc( @@ -1751,7 +1777,7 @@ impl EmitterWriter { ); } } - if show_diff { + if let DisplaySuggestion::Diff = show_code_change { // Colorize removal with red in diff format. buffer.set_style_range( row_num - 2, @@ -1782,7 +1808,7 @@ impl EmitterWriter { // if we elided some lines, add an ellipsis if lines.next().is_some() { buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber); - } else if !show_underline { + } else if let DisplaySuggestion::None = show_code_change { draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1); row_num += 1; } @@ -2066,8 +2092,9 @@ fn num_decimal_digits(num: usize) -> usize { // We replace some characters so the CLI output is always consistent and underlines aligned. const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[ ('\t', " "), // We do our own tab replacement + ('\u{200D}', ""), // Replace ZWJ with nothing for consistent terminal output of grapheme clusters. ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently - ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk + ('\u{202B}', ""), // supported across CLIs and can cause confusion due to the bytes on disk ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always. ('\u{202E}', ""), ('\u{2066}', ""), @@ -2077,7 +2104,7 @@ const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[ ('\u{2069}', ""), ]; -fn replace_tabs(str: &str) -> String { +fn normalize_whitespace(str: &str) -> String { let mut s = str.to_string(); for (c, replacement) in OUTPUT_REPLACEMENTS { s = s.replace(*c, replacement); |
