Strip code to the left and right in diagnostics for long lines

This commit is contained in:
Esteban Küber 2019-07-24 17:58:29 -07:00
parent 7b0085a613
commit 0e668e0496
6 changed files with 133 additions and 47 deletions

View File

@ -179,6 +179,7 @@ pub struct EmitterWriter {
sm: Option<Lrc<SourceMapperDyn>>,
short_message: bool,
teach: bool,
strip_margin: bool,
ui_testing: bool,
}
@ -201,6 +202,7 @@ pub fn stderr(color_config: ColorConfig,
sm: source_map,
short_message,
teach,
strip_margin: false,
ui_testing: false,
}
}
@ -217,6 +219,7 @@ pub fn new(
sm: source_map,
short_message,
teach,
strip_margin: false,
ui_testing: false,
}
}
@ -234,12 +237,29 @@ fn maybe_anonymized(&self, line_num: usize) -> String {
}
}
fn render_source_line(&self,
buffer: &mut StyledBuffer,
file: Lrc<SourceFile>,
line: &Line,
width_offset: usize,
code_offset: usize) -> Vec<(usize, Style)> {
fn render_source_line(
&self,
buffer: &mut StyledBuffer,
file: Lrc<SourceFile>,
line: &Line,
width_offset: usize,
code_offset: usize,
margin: usize,
right_span_margin: usize
) -> Vec<(usize, Style)> {
// Draw:
//
// LL | ... code ...
// | ^^-^ span label
// | |
// | secondary span label
//
// ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it
// | | | |
// | | | actual code found in your source code and the spans we use to mark it
// | | when there's too much wasted space to the left, we trim it to focus where it matters
// | vertical divider between the column number and the code
// column number
if line.line_index == 0 {
return Vec::new();
}
@ -251,12 +271,28 @@ fn render_source_line(&self,
let line_offset = buffer.num_lines();
// First create the source line we will highlight.
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
buffer.puts(line_offset,
0,
&self.maybe_anonymized(line.line_index),
Style::LineNumber);
let left_margin = std::cmp::min(margin, source_string.len());
let right_margin = if source_string.len() > right_span_margin + 120 {
right_span_margin + 120
} else {
source_string.len()
};
// Create the source line we will highlight.
buffer.puts(
line_offset,
code_offset,
&source_string[left_margin..right_margin], // On long lines, we strip the source line
Style::Quotation,
);
if margin > 0 { // We have stripped some code/whitespace from the beginning, make it clear.
buffer.puts(line_offset, code_offset, "...", Style::LineNumber);
}
if right_margin != source_string.len() {
// We have stripped some code after the right-most span end, make it clear we did so.
let offset = code_offset + right_margin - left_margin;
buffer.puts(line_offset, offset, "...", Style::LineNumber);
}
buffer.puts(line_offset, 0, &self.maybe_anonymized(line.line_index), Style::LineNumber);
draw_col_separator(buffer, line_offset, width_offset - 2);
@ -279,18 +315,13 @@ fn render_source_line(&self,
if line.annotations.len() == 1 {
if let Some(ref ann) = line.annotations.get(0) {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
if source_string.chars()
.take(ann.start_col)
.all(|c| c.is_whitespace()) {
if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
let style = if ann.is_primary {
Style::UnderlinePrimary
} else {
Style::UnderlineSecondary
};
buffer.putc(line_offset,
width_offset + depth - 1,
'/',
style);
buffer.putc(line_offset, width_offset + depth - 1, '/', style);
return vec![(depth, style)];
}
}
@ -515,13 +546,13 @@ fn render_source_line(&self,
'_',
line_offset + pos,
width_offset + depth,
code_offset + annotation.start_col,
code_offset + annotation.start_col - margin,
style);
}
_ if self.teach => {
buffer.set_style_range(line_offset,
code_offset + annotation.start_col,
code_offset + annotation.end_col,
code_offset + annotation.start_col - margin,
code_offset + annotation.end_col - margin,
style,
annotation.is_primary);
}
@ -551,7 +582,7 @@ fn render_source_line(&self,
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
for p in line_offset + 1..=line_offset + pos {
buffer.putc(p,
code_offset + annotation.start_col,
code_offset + annotation.start_col - margin,
'|',
style);
}
@ -595,9 +626,9 @@ fn render_source_line(&self,
Style::LabelSecondary
};
let (pos, col) = if pos == 0 {
(pos + 1, annotation.end_col + 1)
(pos + 1, annotation.end_col + 1 - margin)
} else {
(pos + 2, annotation.start_col)
(pos + 2, annotation.start_col - margin)
};
if let Some(ref label) = annotation.label {
buffer.puts(line_offset + pos,
@ -639,7 +670,7 @@ fn render_source_line(&self,
};
for p in annotation.start_col..annotation.end_col {
buffer.putc(line_offset + 1,
code_offset + p,
code_offset + p - margin,
underline,
style);
}
@ -1037,6 +1068,51 @@ fn emit_message_default(
// Contains the vertical lines' positions for active multiline annotations
let mut multilines = FxHashMap::default();
// Get the left-side margin to remove it
let mut margin = std::usize::MAX;
for line_idx in 0..annotated_file.lines.len() {
let file = annotated_file.file.clone();
let line = &annotated_file.lines[line_idx];
if let Some(source_string) = file.get_line(line.line_index - 1) {
let leading_whitespace = source_string
.chars()
.take_while(|c| c.is_whitespace())
.count();
if source_string.chars().any(|c| !c.is_whitespace()) {
margin = std::cmp::min(margin, leading_whitespace);
}
}
}
if margin >= 20 { // On errors with generous margins, trim it
margin = margin - 16; // Keep at least 4 spaces margin
} else if margin == std::usize::MAX || !self.strip_margin {
margin = 0;
}
// Left-most column any visible span points at.
let mut span_left_margin = std::usize::MAX;
for line in &annotated_file.lines {
for ann in &line.annotations {
span_left_margin = std::cmp::min(span_left_margin, ann.start_col);
span_left_margin = std::cmp::min(span_left_margin, ann.end_col);
}
}
if span_left_margin == std::usize::MAX {
span_left_margin = 0;
}
if span_left_margin > 160 {
margin = std::cmp::max(margin, span_left_margin - 100);
}
// Right-most column any visible span points at.
let mut span_right_margin = 0;
for line in &annotated_file.lines {
for ann in &line.annotations {
span_right_margin = std::cmp::max(span_right_margin, ann.start_col);
span_right_margin = std::cmp::max(span_right_margin, ann.end_col);
}
}
// Next, output the annotate source for this file
for line_idx in 0..annotated_file.lines.len() {
let previous_buffer_line = buffer.num_lines();
@ -1048,11 +1124,15 @@ fn emit_message_default(
width_offset + annotated_file.multiline_depth + 1
};
let depths = self.render_source_line(&mut buffer,
annotated_file.file.clone(),
&annotated_file.lines[line_idx],
width_offset,
code_offset);
let depths = self.render_source_line(
&mut buffer,
annotated_file.file.clone(),
&annotated_file.lines[line_idx],
width_offset,
code_offset,
margin,
span_right_margin,
);
let mut to_add = FxHashMap::default();
@ -1107,9 +1187,15 @@ fn emit_message_default(
draw_col_separator(&mut buffer,
last_buffer_line_num,
1 + max_line_num_len);
let left_margin = std::cmp::min(margin, unannotated_line.len());
let right_margin = if unannotated_line.len() > span_right_margin + 120 {
span_right_margin + 120
} else {
unannotated_line.len()
};
buffer.puts(last_buffer_line_num,
code_offset,
&unannotated_line,
&unannotated_line[left_margin..right_margin],
Style::Quotation);
for (depth, style) in &multilines {

View File

@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr),
error[E0669]: invalid value for constraint in inline assembly
--> $DIR/inline-asm-bad-operand.rs:56:32
|
LL | "r"("hello e0669"));
| ^^^^^^^^^^^^^
LL | ... "r"("hello e0669"));
| ^^^^^^^^^^^^^
error: aborting due to 7 previous errors

View File

@ -38,8 +38,8 @@ LL | if let SoulHistory { corridors_of_light,
warning: variable `hours_are_suns` is assigned to, but never used
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:30
|
LL | mut hours_are_suns,
| ^^^^^^^^^^^^^^
LL | ... mut hours_are_suns,
| ^^^^^^^^^^^^^^
|
= note: consider using `_hours_are_suns` instead

View File

@ -1,8 +1,8 @@
error[E0615]: attempted to take value of method `get_x` on type `Point`
--> $DIR/method-missing-call.rs:22:26
|
LL | .get_x;
| ^^^^^ help: use parentheses to call the method: `get_x()`
LL | ... .get_x;
| ^^^^^ help: use parentheses to call the method: `get_x()`
error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter<std::iter::Map<std::slice::Iter<'_, {integer}>, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>`
--> $DIR/method-missing-call.rs:29:16

View File

@ -1,11 +1,11 @@
error[E0499]: cannot borrow `*f` as mutable more than once at a time
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27
|
LL | (f.c)(f, true);
| ----- ^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
| first borrow later used by call
LL | ... (f.c)(f, true);
| ----- ^ second mutable borrow occurs here
| |
| first mutable borrow occurs here
| first borrow later used by call
error[E0382]: borrow of moved value: `f`
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5

View File

@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize,
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:42:36
|
LL | &'b isize,
| ^^ undeclared lifetime
LL | ... &'b isize,
| ^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'b`
--> $DIR/regions-name-undeclared.rs:45:36
|
LL | &'b isize)>,
| ^^ undeclared lifetime
LL | ... &'b isize)>,
| ^^ undeclared lifetime
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/regions-name-undeclared.rs:46:17