use Destination::*;
use rustc_span::source_map::SourceMap;
-use rustc_span::{SourceFile, Span};
+use rustc_span::{FileLines, SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
fn emit_suggestion_default(
&mut self,
+ span: &MultiSpan,
suggestion: &CodeSuggestion,
args: &FluentArgs<'_>,
level: &Level,
let has_deletion = parts.iter().any(|p| p.is_deletion());
let is_multiline = complete.lines().count() > 1;
- enum DisplaySuggestion {
- Underline,
- Diff,
- None,
+ if let Some(span) = span.primary_span() {
+ // Compare the primary span of the diagnostic with the span of the suggestion
+ // being emitted. If they belong to the same file, we don't *need* to show the
+ // file name, saving in verbosity, but if it *isn't* we do need it, otherwise we're
+ // telling users to make a change but not clarifying *where*.
+ let loc = sm.lookup_char_pos(parts[0].span.lo());
+ if loc.file.name != sm.span_to_filename(span) && loc.file.name.is_real() {
+ buffer.puts(row_num - 1, 0, "--> ", Style::LineNumber);
+ buffer.append(
+ row_num - 1,
+ &format!(
+ "{}:{}:{}",
+ sm.filename_for_diagnostics(&loc.file.name),
+ sm.doctest_offset_line(&loc.file.name, loc.line),
+ loc.col.0 + 1,
+ ),
+ Style::LineAndColumn,
+ );
+ for _ in 0..max_line_num_len {
+ buffer.prepend(row_num - 1, " ", Style::NoStyle);
+ }
+ row_num += 1;
+ }
}
-
let show_code_change = if has_deletion && !is_multiline {
DisplaySuggestion::Diff
} else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
assert!(!file_lines.lines.is_empty() || parts[0].span.is_dummy());
let line_start = sm.lookup_char_pos(parts[0].span.lo()).line;
- draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
+ draw_col_separator_no_space(&mut buffer, row_num - 1, max_line_num_len + 1);
let mut lines = complete.lines();
if lines.clone().next().is_none() {
// Account for a suggestion to completely remove a line(s) with whitespace (#94192).
}
row_num += line_end - line_start;
}
- for (line_pos, (line, highlight_parts)) in
- lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
- {
- // Print the span column to avoid confusion
- buffer.puts(
- row_num,
- 0,
- &self.maybe_anonymized(line_start + line_pos),
- Style::LineNumber,
- );
- 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) {
- // N + fn foo(bar: impl T) {
- buffer.puts(
- row_num - 1,
- 0,
- &self.maybe_anonymized(line_start + line_pos),
- Style::LineNumber,
- );
- buffer.puts(row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
- buffer.puts(
- row_num - 1,
- max_line_num_len + 3,
- &normalize_whitespace(
- &*file_lines
- .file
- .get_line(file_lines.lines[line_pos].line_index)
- .unwrap(),
- ),
- Style::NoStyle,
- );
- buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
- } else if is_multiline {
- match &highlight_parts[..] {
- [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
- buffer.puts(row_num, max_line_num_len + 1, "+ ", Style::Addition);
- }
- [] => {
- draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
- }
- _ => {
- buffer.puts(row_num, max_line_num_len + 1, "~ ", Style::Addition);
- }
- }
- } else {
- draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
+ let mut unhighlighted_lines = Vec::new();
+ for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() {
+ debug!(%line_pos, %line, ?highlight_parts);
+
+ // Remember lines that are not highlighted to hide them if needed
+ if highlight_parts.is_empty() {
+ unhighlighted_lines.push((line_pos, line));
+ continue;
}
- // print the suggestion
- buffer.append(row_num, &normalize_whitespace(line), Style::NoStyle);
+ match unhighlighted_lines.len() {
+ 0 => (),
+ // Since we show first line, "..." line and last line,
+ // There is no reason to hide if there are 3 or less lines
+ // (because then we just replace a line with ... which is
+ // not helpful)
+ n if n <= 3 => unhighlighted_lines.drain(..).for_each(|(p, l)| {
+ self.draw_code_line(
+ &mut buffer,
+ &mut row_num,
+ &Vec::new(),
+ p,
+ l,
+ line_start,
+ show_code_change,
+ max_line_num_len,
+ &file_lines,
+ is_multiline,
+ )
+ }),
+ // Print first unhighlighted line, "..." and last unhighlighted line, like so:
+ //
+ // LL | this line was highlighted
+ // LL | this line is just for context
+ // ...
+ // LL | this line is just for context
+ // LL | this line was highlighted
+ _ => {
+ let last_line = unhighlighted_lines.pop();
+ let first_line = unhighlighted_lines.drain(..).next();
+
+ first_line.map(|(p, l)| {
+ self.draw_code_line(
+ &mut buffer,
+ &mut row_num,
+ &Vec::new(),
+ p,
+ l,
+ line_start,
+ show_code_change,
+ max_line_num_len,
+ &file_lines,
+ is_multiline,
+ )
+ });
- // Colorize addition/replacements with green.
- for &SubstitutionHighlight { start, end } in highlight_parts {
- // Account for tabs when highlighting (#87972).
- let tabs: usize = line
- .chars()
- .take(start)
- .map(|ch| match ch {
- '\t' => 3,
- _ => 0,
- })
- .sum();
- buffer.set_style_range(
- row_num,
- max_line_num_len + 3 + start + tabs,
- max_line_num_len + 3 + end + tabs,
- Style::Addition,
- true,
- );
+ buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
+ row_num += 1;
+
+ last_line.map(|(p, l)| {
+ self.draw_code_line(
+ &mut buffer,
+ &mut row_num,
+ &Vec::new(),
+ p,
+ l,
+ line_start,
+ show_code_change,
+ max_line_num_len,
+ &file_lines,
+ is_multiline,
+ )
+ });
+ }
}
- row_num += 1;
+
+ self.draw_code_line(
+ &mut buffer,
+ &mut row_num,
+ highlight_parts,
+ line_pos,
+ line,
+ line_start,
+ show_code_change,
+ max_line_num_len,
+ &file_lines,
+ is_multiline,
+ )
}
// This offset and the ones below need to be signed to account for replacement code
) {
panic!("failed to emit error: {}", e);
}
- } else if let Err(e) =
- self.emit_suggestion_default(sugg, args, &Level::Help, max_line_num_len)
- {
+ } else if let Err(e) = self.emit_suggestion_default(
+ span,
+ sugg,
+ args,
+ &Level::Help,
+ max_line_num_len,
+ ) {
panic!("failed to emit error: {}", e);
};
}
}
}
}
+
+ fn draw_code_line(
+ &self,
+ buffer: &mut StyledBuffer,
+ row_num: &mut usize,
+ highlight_parts: &Vec<SubstitutionHighlight>,
+ line_pos: usize,
+ line: &str,
+ line_start: usize,
+ show_code_change: DisplaySuggestion,
+ max_line_num_len: usize,
+ file_lines: &FileLines,
+ is_multiline: bool,
+ ) {
+ // Print the span column to avoid confusion
+ buffer.puts(*row_num, 0, &self.maybe_anonymized(line_start + line_pos), Style::LineNumber);
+ 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) {
+ // N + fn foo(bar: impl T) {
+ buffer.puts(
+ *row_num - 1,
+ 0,
+ &self.maybe_anonymized(line_start + line_pos),
+ Style::LineNumber,
+ );
+ buffer.puts(*row_num - 1, max_line_num_len + 1, "- ", Style::Removal);
+ buffer.puts(
+ *row_num - 1,
+ max_line_num_len + 3,
+ &normalize_whitespace(
+ &*file_lines.file.get_line(file_lines.lines[line_pos].line_index).unwrap(),
+ ),
+ Style::NoStyle,
+ );
+ buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ } else if is_multiline {
+ match &highlight_parts[..] {
+ [SubstitutionHighlight { start: 0, end }] if *end == line.len() => {
+ buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ }
+ [] => {
+ draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+ }
+ _ => {
+ buffer.puts(*row_num, max_line_num_len + 1, "~ ", Style::Addition);
+ }
+ }
+ } else {
+ draw_col_separator(buffer, *row_num, max_line_num_len + 1);
+ }
+
+ // print the suggestion
+ buffer.append(*row_num, &normalize_whitespace(line), Style::NoStyle);
+
+ // Colorize addition/replacements with green.
+ for &SubstitutionHighlight { start, end } in highlight_parts {
+ // Account for tabs when highlighting (#87972).
+ let tabs: usize = line
+ .chars()
+ .take(start)
+ .map(|ch| match ch {
+ '\t' => 3,
+ _ => 0,
+ })
+ .sum();
+ buffer.set_style_range(
+ *row_num,
+ max_line_num_len + 3 + start + tabs,
+ max_line_num_len + 3 + end + tabs,
+ Style::Addition,
+ true,
+ );
+ }
+ *row_num += 1;
+ }
+}
+
+#[derive(Clone, Copy)]
+enum DisplaySuggestion {
+ Underline,
+ Diff,
+ None,
}
impl FileWithAnnotatedLines {