Skip to content

Commit 0e668e0

Browse files
committed
Strip code to the left and right in diagnostics for long lines
1 parent 7b0085a commit 0e668e0

File tree

6 files changed

+133
-47
lines changed

6 files changed

+133
-47
lines changed

src/librustc_errors/emitter.rs

Lines changed: 118 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ pub struct EmitterWriter {
179179
sm: Option<Lrc<SourceMapperDyn>>,
180180
short_message: bool,
181181
teach: bool,
182+
strip_margin: bool,
182183
ui_testing: bool,
183184
}
184185

@@ -201,6 +202,7 @@ impl EmitterWriter {
201202
sm: source_map,
202203
short_message,
203204
teach,
205+
strip_margin: false,
204206
ui_testing: false,
205207
}
206208
}
@@ -217,6 +219,7 @@ impl EmitterWriter {
217219
sm: source_map,
218220
short_message,
219221
teach,
222+
strip_margin: false,
220223
ui_testing: false,
221224
}
222225
}
@@ -234,12 +237,29 @@ impl EmitterWriter {
234237
}
235238
}
236239

237-
fn render_source_line(&self,
238-
buffer: &mut StyledBuffer,
239-
file: Lrc<SourceFile>,
240-
line: &Line,
241-
width_offset: usize,
242-
code_offset: usize) -> Vec<(usize, Style)> {
240+
fn render_source_line(
241+
&self,
242+
buffer: &mut StyledBuffer,
243+
file: Lrc<SourceFile>,
244+
line: &Line,
245+
width_offset: usize,
246+
code_offset: usize,
247+
margin: usize,
248+
right_span_margin: usize
249+
) -> Vec<(usize, Style)> {
250+
// Draw:
251+
//
252+
// LL | ... code ...
253+
// | ^^-^ span label
254+
// | |
255+
// | secondary span label
256+
//
257+
// ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it
258+
// | | | |
259+
// | | | actual code found in your source code and the spans we use to mark it
260+
// | | when there's too much wasted space to the left, we trim it to focus where it matters
261+
// | vertical divider between the column number and the code
262+
// column number
243263
if line.line_index == 0 {
244264
return Vec::new();
245265
}
@@ -251,12 +271,28 @@ impl EmitterWriter {
251271

252272
let line_offset = buffer.num_lines();
253273

254-
// First create the source line we will highlight.
255-
buffer.puts(line_offset, code_offset, &source_string, Style::Quotation);
256-
buffer.puts(line_offset,
257-
0,
258-
&self.maybe_anonymized(line.line_index),
259-
Style::LineNumber);
274+
let left_margin = std::cmp::min(margin, source_string.len());
275+
let right_margin = if source_string.len() > right_span_margin + 120 {
276+
right_span_margin + 120
277+
} else {
278+
source_string.len()
279+
};
280+
// Create the source line we will highlight.
281+
buffer.puts(
282+
line_offset,
283+
code_offset,
284+
&source_string[left_margin..right_margin], // On long lines, we strip the source line
285+
Style::Quotation,
286+
);
287+
if margin > 0 { // We have stripped some code/whitespace from the beginning, make it clear.
288+
buffer.puts(line_offset, code_offset, "...", Style::LineNumber);
289+
}
290+
if right_margin != source_string.len() {
291+
// We have stripped some code after the right-most span end, make it clear we did so.
292+
let offset = code_offset + right_margin - left_margin;
293+
buffer.puts(line_offset, offset, "...", Style::LineNumber);
294+
}
295+
buffer.puts(line_offset, 0, &self.maybe_anonymized(line.line_index), Style::LineNumber);
260296

261297
draw_col_separator(buffer, line_offset, width_offset - 2);
262298

@@ -279,18 +315,13 @@ impl EmitterWriter {
279315
if line.annotations.len() == 1 {
280316
if let Some(ref ann) = line.annotations.get(0) {
281317
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
282-
if source_string.chars()
283-
.take(ann.start_col)
284-
.all(|c| c.is_whitespace()) {
318+
if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
285319
let style = if ann.is_primary {
286320
Style::UnderlinePrimary
287321
} else {
288322
Style::UnderlineSecondary
289323
};
290-
buffer.putc(line_offset,
291-
width_offset + depth - 1,
292-
'/',
293-
style);
324+
buffer.putc(line_offset, width_offset + depth - 1, '/', style);
294325
return vec![(depth, style)];
295326
}
296327
}
@@ -515,13 +546,13 @@ impl EmitterWriter {
515546
'_',
516547
line_offset + pos,
517548
width_offset + depth,
518-
code_offset + annotation.start_col,
549+
code_offset + annotation.start_col - margin,
519550
style);
520551
}
521552
_ if self.teach => {
522553
buffer.set_style_range(line_offset,
523-
code_offset + annotation.start_col,
524-
code_offset + annotation.end_col,
554+
code_offset + annotation.start_col - margin,
555+
code_offset + annotation.end_col - margin,
525556
style,
526557
annotation.is_primary);
527558
}
@@ -551,7 +582,7 @@ impl EmitterWriter {
551582
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
552583
for p in line_offset + 1..=line_offset + pos {
553584
buffer.putc(p,
554-
code_offset + annotation.start_col,
585+
code_offset + annotation.start_col - margin,
555586
'|',
556587
style);
557588
}
@@ -595,9 +626,9 @@ impl EmitterWriter {
595626
Style::LabelSecondary
596627
};
597628
let (pos, col) = if pos == 0 {
598-
(pos + 1, annotation.end_col + 1)
629+
(pos + 1, annotation.end_col + 1 - margin)
599630
} else {
600-
(pos + 2, annotation.start_col)
631+
(pos + 2, annotation.start_col - margin)
601632
};
602633
if let Some(ref label) = annotation.label {
603634
buffer.puts(line_offset + pos,
@@ -639,7 +670,7 @@ impl EmitterWriter {
639670
};
640671
for p in annotation.start_col..annotation.end_col {
641672
buffer.putc(line_offset + 1,
642-
code_offset + p,
673+
code_offset + p - margin,
643674
underline,
644675
style);
645676
}
@@ -1037,6 +1068,51 @@ impl EmitterWriter {
10371068
// Contains the vertical lines' positions for active multiline annotations
10381069
let mut multilines = FxHashMap::default();
10391070

1071+
// Get the left-side margin to remove it
1072+
let mut margin = std::usize::MAX;
1073+
for line_idx in 0..annotated_file.lines.len() {
1074+
let file = annotated_file.file.clone();
1075+
let line = &annotated_file.lines[line_idx];
1076+
if let Some(source_string) = file.get_line(line.line_index - 1) {
1077+
let leading_whitespace = source_string
1078+
.chars()
1079+
.take_while(|c| c.is_whitespace())
1080+
.count();
1081+
if source_string.chars().any(|c| !c.is_whitespace()) {
1082+
margin = std::cmp::min(margin, leading_whitespace);
1083+
}
1084+
}
1085+
}
1086+
if margin >= 20 { // On errors with generous margins, trim it
1087+
margin = margin - 16; // Keep at least 4 spaces margin
1088+
} else if margin == std::usize::MAX || !self.strip_margin {
1089+
margin = 0;
1090+
}
1091+
1092+
// Left-most column any visible span points at.
1093+
let mut span_left_margin = std::usize::MAX;
1094+
for line in &annotated_file.lines {
1095+
for ann in &line.annotations {
1096+
span_left_margin = std::cmp::min(span_left_margin, ann.start_col);
1097+
span_left_margin = std::cmp::min(span_left_margin, ann.end_col);
1098+
}
1099+
}
1100+
if span_left_margin == std::usize::MAX {
1101+
span_left_margin = 0;
1102+
}
1103+
if span_left_margin > 160 {
1104+
margin = std::cmp::max(margin, span_left_margin - 100);
1105+
}
1106+
1107+
// Right-most column any visible span points at.
1108+
let mut span_right_margin = 0;
1109+
for line in &annotated_file.lines {
1110+
for ann in &line.annotations {
1111+
span_right_margin = std::cmp::max(span_right_margin, ann.start_col);
1112+
span_right_margin = std::cmp::max(span_right_margin, ann.end_col);
1113+
}
1114+
}
1115+
10401116
// Next, output the annotate source for this file
10411117
for line_idx in 0..annotated_file.lines.len() {
10421118
let previous_buffer_line = buffer.num_lines();
@@ -1048,11 +1124,15 @@ impl EmitterWriter {
10481124
width_offset + annotated_file.multiline_depth + 1
10491125
};
10501126

1051-
let depths = self.render_source_line(&mut buffer,
1052-
annotated_file.file.clone(),
1053-
&annotated_file.lines[line_idx],
1054-
width_offset,
1055-
code_offset);
1127+
let depths = self.render_source_line(
1128+
&mut buffer,
1129+
annotated_file.file.clone(),
1130+
&annotated_file.lines[line_idx],
1131+
width_offset,
1132+
code_offset,
1133+
margin,
1134+
span_right_margin,
1135+
);
10561136

10571137
let mut to_add = FxHashMap::default();
10581138

@@ -1107,9 +1187,15 @@ impl EmitterWriter {
11071187
draw_col_separator(&mut buffer,
11081188
last_buffer_line_num,
11091189
1 + max_line_num_len);
1190+
let left_margin = std::cmp::min(margin, unannotated_line.len());
1191+
let right_margin = if unannotated_line.len() > span_right_margin + 120 {
1192+
span_right_margin + 120
1193+
} else {
1194+
unannotated_line.len()
1195+
};
11101196
buffer.puts(last_buffer_line_num,
11111197
code_offset,
1112-
&unannotated_line,
1198+
&unannotated_line[left_margin..right_margin],
11131199
Style::Quotation);
11141200

11151201
for (depth, style) in &multilines {

src/test/ui/inline-asm-bad-operand.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ LL | asm!("mov sp, $0"::"r"(addr),
3737
error[E0669]: invalid value for constraint in inline assembly
3838
--> $DIR/inline-asm-bad-operand.rs:56:32
3939
|
40-
LL | "r"("hello e0669"));
41-
| ^^^^^^^^^^^^^
40+
LL | ... "r"("hello e0669"));
41+
| ^^^^^^^^^^^^^
4242

4343
error: aborting due to 7 previous errors
4444

src/test/ui/lint/issue-47390-unused-variable-in-struct-pattern.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ LL | if let SoulHistory { corridors_of_light,
3838
warning: variable `hours_are_suns` is assigned to, but never used
3939
--> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:30
4040
|
41-
LL | mut hours_are_suns,
42-
| ^^^^^^^^^^^^^^
41+
LL | ... mut hours_are_suns,
42+
| ^^^^^^^^^^^^^^
4343
|
4444
= note: consider using `_hours_are_suns` instead
4545

src/test/ui/methods/method-missing-call.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
error[E0615]: attempted to take value of method `get_x` on type `Point`
22
--> $DIR/method-missing-call.rs:22:26
33
|
4-
LL | .get_x;
5-
| ^^^^^ help: use parentheses to call the method: `get_x()`
4+
LL | ... .get_x;
5+
| ^^^^^ help: use parentheses to call the method: `get_x()`
66

77
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]>`
88
--> $DIR/method-missing-call.rs:29:16

src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0499]: cannot borrow `*f` as mutable more than once at a time
22
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27
33
|
4-
LL | (f.c)(f, true);
5-
| ----- ^ second mutable borrow occurs here
6-
| |
7-
| first mutable borrow occurs here
8-
| first borrow later used by call
4+
LL | ... (f.c)(f, true);
5+
| ----- ^ second mutable borrow occurs here
6+
| |
7+
| first mutable borrow occurs here
8+
| first borrow later used by call
99

1010
error[E0382]: borrow of moved value: `f`
1111
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5

src/test/ui/regions/regions-name-undeclared.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ LL | fn fn_types(a: &'a isize,
4949
error[E0261]: use of undeclared lifetime name `'b`
5050
--> $DIR/regions-name-undeclared.rs:42:36
5151
|
52-
LL | &'b isize,
53-
| ^^ undeclared lifetime
52+
LL | ... &'b isize,
53+
| ^^ undeclared lifetime
5454

5555
error[E0261]: use of undeclared lifetime name `'b`
5656
--> $DIR/regions-name-undeclared.rs:45:36
5757
|
58-
LL | &'b isize)>,
59-
| ^^ undeclared lifetime
58+
LL | ... &'b isize)>,
59+
| ^^ undeclared lifetime
6060

6161
error[E0261]: use of undeclared lifetime name `'a`
6262
--> $DIR/regions-name-undeclared.rs:46:17

0 commit comments

Comments
 (0)