@@ -179,6 +179,7 @@ pub struct EmitterWriter {
179
179
sm: Option<Lrc<SourceMapperDyn>>,
180
180
short_message: bool,
181
181
teach: bool,
182
+ strip_margin: bool,
182
183
ui_testing: bool,
183
184
}
184
185
@@ -201,6 +202,7 @@ impl EmitterWriter {
201
202
sm: source_map,
202
203
short_message,
203
204
teach,
205
+ strip_margin: false,
204
206
ui_testing: false,
205
207
}
206
208
}
@@ -217,6 +219,7 @@ impl EmitterWriter {
217
219
sm: source_map,
218
220
short_message,
219
221
teach,
222
+ strip_margin: false,
220
223
ui_testing: false,
221
224
}
222
225
}
@@ -234,12 +237,29 @@ impl EmitterWriter {
234
237
}
235
238
}
236
239
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
243
263
if line.line_index == 0 {
244
264
return Vec::new();
245
265
}
@@ -251,12 +271,28 @@ impl EmitterWriter {
251
271
252
272
let line_offset = buffer.num_lines();
253
273
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);
260
296
261
297
draw_col_separator(buffer, line_offset, width_offset - 2);
262
298
@@ -279,18 +315,13 @@ impl EmitterWriter {
279
315
if line.annotations.len() == 1 {
280
316
if let Some(ref ann) = line.annotations.get(0) {
281
317
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()) {
285
319
let style = if ann.is_primary {
286
320
Style::UnderlinePrimary
287
321
} else {
288
322
Style::UnderlineSecondary
289
323
};
290
- buffer.putc(line_offset,
291
- width_offset + depth - 1,
292
- '/',
293
- style);
324
+ buffer.putc(line_offset, width_offset + depth - 1, '/', style);
294
325
return vec![(depth, style)];
295
326
}
296
327
}
@@ -515,13 +546,13 @@ impl EmitterWriter {
515
546
'_',
516
547
line_offset + pos,
517
548
width_offset + depth,
518
- code_offset + annotation.start_col,
549
+ code_offset + annotation.start_col - margin ,
519
550
style);
520
551
}
521
552
_ if self.teach => {
522
553
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 ,
525
556
style,
526
557
annotation.is_primary);
527
558
}
@@ -551,7 +582,7 @@ impl EmitterWriter {
551
582
if pos > 1 && (annotation.has_label() || annotation.takes_space()) {
552
583
for p in line_offset + 1..=line_offset + pos {
553
584
buffer.putc(p,
554
- code_offset + annotation.start_col,
585
+ code_offset + annotation.start_col - margin ,
555
586
'|',
556
587
style);
557
588
}
@@ -595,9 +626,9 @@ impl EmitterWriter {
595
626
Style::LabelSecondary
596
627
};
597
628
let (pos, col) = if pos == 0 {
598
- (pos + 1, annotation.end_col + 1)
629
+ (pos + 1, annotation.end_col + 1 - margin )
599
630
} else {
600
- (pos + 2, annotation.start_col)
631
+ (pos + 2, annotation.start_col - margin )
601
632
};
602
633
if let Some(ref label) = annotation.label {
603
634
buffer.puts(line_offset + pos,
@@ -639,7 +670,7 @@ impl EmitterWriter {
639
670
};
640
671
for p in annotation.start_col..annotation.end_col {
641
672
buffer.putc(line_offset + 1,
642
- code_offset + p,
673
+ code_offset + p - margin ,
643
674
underline,
644
675
style);
645
676
}
@@ -1037,6 +1068,51 @@ impl EmitterWriter {
1037
1068
// Contains the vertical lines' positions for active multiline annotations
1038
1069
let mut multilines = FxHashMap::default();
1039
1070
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
+
1040
1116
// Next, output the annotate source for this file
1041
1117
for line_idx in 0..annotated_file.lines.len() {
1042
1118
let previous_buffer_line = buffer.num_lines();
@@ -1048,11 +1124,15 @@ impl EmitterWriter {
1048
1124
width_offset + annotated_file.multiline_depth + 1
1049
1125
};
1050
1126
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
+ );
1056
1136
1057
1137
let mut to_add = FxHashMap::default();
1058
1138
@@ -1107,9 +1187,15 @@ impl EmitterWriter {
1107
1187
draw_col_separator(&mut buffer,
1108
1188
last_buffer_line_num,
1109
1189
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
+ };
1110
1196
buffer.puts(last_buffer_line_num,
1111
1197
code_offset,
1112
- &unannotated_line,
1198
+ &unannotated_line[left_margin..right_margin] ,
1113
1199
Style::Quotation);
1114
1200
1115
1201
for (depth, style) in &multilines {
0 commit comments