1
Fork 0

Modify structured suggestion output

* On suggestions that include deletions, use a diff inspired output format
* When suggesting addition, use `+` as underline
* Color highlight modified span
This commit is contained in:
Esteban Küber 2021-06-21 19:07:19 -07:00 committed by Esteban Kuber
parent d488de82f3
commit 99f2977031
881 changed files with 4696 additions and 3326 deletions

View file

@ -14,7 +14,10 @@ use rustc_span::{MultiSpan, SourceFile, Span};
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SuggestionStyle};
use crate::{
CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
};
use rustc_lint_defs::pluralize;
@ -1590,8 +1593,11 @@ impl EmitterWriter {
);
let mut row_num = 2;
draw_col_separator_no_space(&mut buffer, 1, max_line_num_len + 1);
let mut notice_capitalization = false;
for (complete, parts, only_capitalization) in suggestions.iter().take(MAX_SUGGESTIONS) {
for (complete, parts, highlights, only_capitalization) in
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
@ -1599,16 +1605,26 @@ impl EmitterWriter {
let show_underline = !(parts.len() == 1 && parts[0].snippet.trim() == complete.trim())
&& complete.lines().count() == 1;
let lines = sm
let has_deletion = parts.iter().any(|p| p.is_deletion());
let is_multiline = complete.lines().count() > 1;
let show_diff = has_deletion && !is_multiline;
if show_diff {
row_num += 1;
}
let file_lines = sm
.span_to_lines(parts[0].span)
.expect("span_to_lines failed when emitting suggestion");
assert!(!lines.lines.is_empty() || parts[0].span.is_dummy());
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);
let mut lines = complete.lines();
for (line_pos, line) in lines.by_ref().take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
for (line_pos, (line, parts)) in
lines.by_ref().zip(highlights).take(MAX_SUGGESTION_HIGHLIGHT_LINES).enumerate()
{
// Print the span column to avoid confusion
buffer.puts(
@ -1617,9 +1633,60 @@ impl EmitterWriter {
&self.maybe_anonymized(line_start + line_pos),
Style::LineNumber,
);
if show_diff {
// 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,
&replace_tabs(
&*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 &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);
}
// print the suggestion
draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
if is_multiline {
for SubstitutionHighlight { start, end } in parts {
buffer.set_style_range(
row_num,
max_line_num_len + 3 + start,
max_line_num_len + 3 + end,
Style::Addition,
true,
);
}
}
row_num += 1;
}
@ -1654,25 +1721,36 @@ impl EmitterWriter {
let underline_start = (span_start_pos + start) as isize + offset;
let underline_end = (span_start_pos + start + sub_len) as isize + offset;
assert!(underline_start >= 0 && underline_end >= 0);
let padding: usize = max_line_num_len + 3;
for p in underline_start..underline_end {
buffer.putc(
row_num,
((max_line_num_len + 3) as isize + p) as usize,
'^',
Style::UnderlinePrimary,
// Colorize addition/replacements with green.
buffer.set_style(
row_num - 1,
(padding as isize + p) as usize,
Style::Addition,
true,
);
}
// underline removals too
if underline_start == underline_end {
for p in underline_start - 1..underline_start + 1 {
if !show_diff {
// If this is a replacement, underline with `^`, if this is an addition
// underline with `+`.
buffer.putc(
row_num,
((max_line_num_len + 3) as isize + p) as usize,
'-',
Style::UnderlineSecondary,
(padding as isize + p) as usize,
if part.is_addition(&sm) { '+' } else { '~' },
Style::Addition,
);
}
}
if show_diff {
// Colorize removal with red in diff format.
buffer.set_style_range(
row_num - 2,
(padding as isize + span_start_pos as isize) as usize,
(padding as isize + span_end_pos as isize) as usize,
Style::Removal,
true,
);
}
// length of the code after substitution
let full_sub_len = part
@ -2129,6 +2207,12 @@ impl<'a> WritableDst<'a> {
fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
let mut spec = ColorSpec::new();
match style {
Style::Addition => {
spec.set_fg(Some(Color::Green)).set_intense(true);
}
Style::Removal => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Style::LineAndColumn => {}
Style::LineNumber => {
spec.set_bold(true);