Skip to content

Commit 0175871

Browse files
committed
feat: Merge multiline annotations with matching spans
1 parent 9ec2939 commit 0175871

File tree

2 files changed

+63
-12
lines changed

2 files changed

+63
-12
lines changed

src/renderer/display_list.rs

+52
Original file line numberDiff line numberDiff line change
@@ -1248,6 +1248,58 @@ fn format_body(
12481248
let mut depth_map: HashMap<usize, usize> = HashMap::new();
12491249
let mut current_depth = 0;
12501250
let mut annotations = snippet.annotations;
1251+
let ranges = annotations
1252+
.iter()
1253+
.map(|a| a.range.clone())
1254+
.collect::<Vec<_>>();
1255+
// We want to merge multiline annotations that have the same range into one
1256+
// multiline annotation to save space. This is done by making any duplicate
1257+
// multiline annotations into a single-line annotation pointing at the end
1258+
// of the range.
1259+
//
1260+
// 3 | X0 Y0 Z0
1261+
// | _____^
1262+
// | | ____|
1263+
// | || ___|
1264+
// | |||
1265+
// 4 | ||| X1 Y1 Z1
1266+
// 5 | ||| X2 Y2 Z2
1267+
// | ||| ^
1268+
// | |||____|
1269+
// | ||____`X` is a good letter
1270+
// | |____`Y` is a good letter too
1271+
// | `Z` label
1272+
// Should be
1273+
// error: foo
1274+
// --> test.rs:3:3
1275+
// |
1276+
// 3 | / X0 Y0 Z0
1277+
// 4 | | X1 Y1 Z1
1278+
// 5 | | X2 Y2 Z2
1279+
// | | ^
1280+
// | |____|
1281+
// | `X` is a good letter
1282+
// | `Y` is a good letter too
1283+
// | `Z` label
1284+
// |
1285+
ranges.iter().enumerate().for_each(|(r_idx, range)| {
1286+
annotations
1287+
.iter_mut()
1288+
.enumerate()
1289+
.skip(r_idx + 1)
1290+
.for_each(|(ann_idx, ann)| {
1291+
// Skip if the annotation's index matches the range index
1292+
if ann_idx != r_idx
1293+
// We only want to merge multiline annotations
1294+
&& snippet.source[ann.range.clone()].lines().count() > 1
1295+
// We only want to merge annotations that have the same range
1296+
&& ann.range.start == range.start
1297+
&& ann.range.end == range.end
1298+
{
1299+
ann.range.start = ann.range.end.saturating_sub(1);
1300+
}
1301+
});
1302+
});
12511303
annotations.sort_by_key(|a| a.range.start);
12521304
let mut annotations = annotations.into_iter().enumerate().collect::<Vec<_>>();
12531305

tests/rustc_tests.rs

+11-12
Original file line numberDiff line numberDiff line change
@@ -248,22 +248,21 @@ fn foo() {
248248
.annotation(Level::Warning.span(14..38).label("`Z` label")),
249249
);
250250

251+
// This should have a `^` but we currently don't support the idea of a
252+
// "primary" annotation, which would solve this
251253
let expected = str![[r#"
252254
error: foo
253255
--> test.rs:3:3
254256
|
255-
3 | X0 Y0 Z0
256-
| _____-
257-
| | ____|
258-
| || ___|
259-
| |||
260-
4 | ||| X1 Y1 Z1
261-
5 | ||| X2 Y2 Z2
262-
| ||| -
263-
| |||____|
264-
| ||____`X` is a good letter
265-
| |____`Y` is a good letter too
266-
| `Z` label
257+
3 | X0 Y0 Z0
258+
| ___^
259+
4 | | X1 Y1 Z1
260+
5 | | X2 Y2 Z2
261+
| | -
262+
| |____|
263+
| `X` is a good letter
264+
| `Y` is a good letter too
265+
| `Z` label
267266
|
268267
"#]];
269268
let renderer = Renderer::plain();

0 commit comments

Comments
 (0)