@@ -162,6 +162,7 @@ impl ColorConfig {
162
162
}
163
163
}
164
164
165
+ /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
165
166
pub struct EmitterWriter {
166
167
dst : Destination ,
167
168
sm : Option < Lrc < SourceMapperDyn > > ,
@@ -170,7 +171,8 @@ pub struct EmitterWriter {
170
171
ui_testing : bool ,
171
172
}
172
173
173
- struct FileWithAnnotatedLines {
174
+ #[ derive( Debug ) ]
175
+ pub struct FileWithAnnotatedLines {
174
176
file : Lrc < SourceFile > ,
175
177
lines : Vec < Line > ,
176
178
multiline_depth : usize ,
@@ -221,169 +223,6 @@ impl EmitterWriter {
221
223
}
222
224
}
223
225
224
- fn preprocess_annotations ( & mut self , msp : & MultiSpan ) -> Vec < FileWithAnnotatedLines > {
225
- fn add_annotation_to_file ( file_vec : & mut Vec < FileWithAnnotatedLines > ,
226
- file : Lrc < SourceFile > ,
227
- line_index : usize ,
228
- ann : Annotation ) {
229
-
230
- for slot in file_vec. iter_mut ( ) {
231
- // Look through each of our files for the one we're adding to
232
- if slot. file . name == file. name {
233
- // See if we already have a line for it
234
- for line_slot in & mut slot. lines {
235
- if line_slot. line_index == line_index {
236
- line_slot. annotations . push ( ann) ;
237
- return ;
238
- }
239
- }
240
- // We don't have a line yet, create one
241
- slot. lines . push ( Line {
242
- line_index,
243
- annotations : vec ! [ ann] ,
244
- } ) ;
245
- slot. lines . sort ( ) ;
246
- return ;
247
- }
248
- }
249
- // This is the first time we're seeing the file
250
- file_vec. push ( FileWithAnnotatedLines {
251
- file,
252
- lines : vec ! [ Line {
253
- line_index,
254
- annotations: vec![ ann] ,
255
- } ] ,
256
- multiline_depth : 0 ,
257
- } ) ;
258
- }
259
-
260
- let mut output = vec ! [ ] ;
261
- let mut multiline_annotations = vec ! [ ] ;
262
-
263
- if let Some ( ref sm) = self . sm {
264
- for span_label in msp. span_labels ( ) {
265
- if span_label. span . is_dummy ( ) {
266
- continue ;
267
- }
268
-
269
- let lo = sm. lookup_char_pos ( span_label. span . lo ( ) ) ;
270
- let mut hi = sm. lookup_char_pos ( span_label. span . hi ( ) ) ;
271
-
272
- // Watch out for "empty spans". If we get a span like 6..6, we
273
- // want to just display a `^` at 6, so convert that to
274
- // 6..7. This is degenerate input, but it's best to degrade
275
- // gracefully -- and the parser likes to supply a span like
276
- // that for EOF, in particular.
277
-
278
- if lo. col_display == hi. col_display && lo. line == hi. line {
279
- hi. col_display += 1 ;
280
- }
281
-
282
- let ann_type = if lo. line != hi. line {
283
- let ml = MultilineAnnotation {
284
- depth : 1 ,
285
- line_start : lo. line ,
286
- line_end : hi. line ,
287
- start_col : lo. col_display ,
288
- end_col : hi. col_display ,
289
- is_primary : span_label. is_primary ,
290
- label : span_label. label . clone ( ) ,
291
- overlaps_exactly : false ,
292
- } ;
293
- multiline_annotations. push ( ( lo. file . clone ( ) , ml. clone ( ) ) ) ;
294
- AnnotationType :: Multiline ( ml)
295
- } else {
296
- AnnotationType :: Singleline
297
- } ;
298
- let ann = Annotation {
299
- start_col : lo. col_display ,
300
- end_col : hi. col_display ,
301
- is_primary : span_label. is_primary ,
302
- label : span_label. label . clone ( ) ,
303
- annotation_type : ann_type,
304
- } ;
305
-
306
- if !ann. is_multiline ( ) {
307
- add_annotation_to_file ( & mut output, lo. file , lo. line , ann) ;
308
- }
309
- }
310
- }
311
-
312
- // Find overlapping multiline annotations, put them at different depths
313
- multiline_annotations. sort_by_key ( |& ( _, ref ml) | ( ml. line_start , ml. line_end ) ) ;
314
- for item in multiline_annotations. clone ( ) {
315
- let ann = item. 1 ;
316
- for item in multiline_annotations. iter_mut ( ) {
317
- let ref mut a = item. 1 ;
318
- // Move all other multiline annotations overlapping with this one
319
- // one level to the right.
320
- if !( ann. same_span ( a) ) &&
321
- num_overlap ( ann. line_start , ann. line_end , a. line_start , a. line_end , true )
322
- {
323
- a. increase_depth ( ) ;
324
- } else if ann. same_span ( a) && & ann != a {
325
- a. overlaps_exactly = true ;
326
- } else {
327
- break ;
328
- }
329
- }
330
- }
331
-
332
- let mut max_depth = 0 ; // max overlapping multiline spans
333
- for ( file, ann) in multiline_annotations {
334
- if ann. depth > max_depth {
335
- max_depth = ann. depth ;
336
- }
337
- let mut end_ann = ann. as_end ( ) ;
338
- if !ann. overlaps_exactly {
339
- // avoid output like
340
- //
341
- // | foo(
342
- // | _____^
343
- // | |_____|
344
- // | || bar,
345
- // | || );
346
- // | || ^
347
- // | ||______|
348
- // | |______foo
349
- // | baz
350
- //
351
- // and instead get
352
- //
353
- // | foo(
354
- // | _____^
355
- // | | bar,
356
- // | | );
357
- // | | ^
358
- // | | |
359
- // | |______foo
360
- // | baz
361
- add_annotation_to_file ( & mut output, file. clone ( ) , ann. line_start , ann. as_start ( ) ) ;
362
- // 4 is the minimum vertical length of a multiline span when presented: two lines
363
- // of code and two lines of underline. This is not true for the special case where
364
- // the beginning doesn't have an underline, but the current logic seems to be
365
- // working correctly.
366
- let middle = min ( ann. line_start + 4 , ann. line_end ) ;
367
- for line in ann. line_start + 1 ..middle {
368
- // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
369
- add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
370
- }
371
- if middle < ann. line_end - 1 {
372
- for line in ann. line_end - 1 ..ann. line_end {
373
- add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
374
- }
375
- }
376
- } else {
377
- end_ann. annotation_type = AnnotationType :: Singleline ;
378
- }
379
- add_annotation_to_file ( & mut output, file, ann. line_end , end_ann) ;
380
- }
381
- for file_vec in output. iter_mut ( ) {
382
- file_vec. multiline_depth = max_depth;
383
- }
384
- output
385
- }
386
-
387
226
fn render_source_line ( & self ,
388
227
buffer : & mut StyledBuffer ,
389
228
file : Lrc < SourceFile > ,
@@ -1093,9 +932,7 @@ impl EmitterWriter {
1093
932
}
1094
933
}
1095
934
1096
- // Preprocess all the annotations so that they are grouped by file and by line number
1097
- // This helps us quickly iterate over the whole message (including secondary file spans)
1098
- let mut annotated_files = self . preprocess_annotations ( msp) ;
935
+ let mut annotated_files = FileWithAnnotatedLines :: collect_annotations ( msp, & self . sm ) ;
1099
936
1100
937
// Make sure our primary file comes first
1101
938
let ( primary_lo, sm) = if let ( Some ( sm) , Some ( ref primary_span) ) =
@@ -1503,6 +1340,176 @@ impl EmitterWriter {
1503
1340
}
1504
1341
}
1505
1342
1343
+ impl FileWithAnnotatedLines {
1344
+ /// Preprocess all the annotations so that they are grouped by file and by line number
1345
+ /// This helps us quickly iterate over the whole message (including secondary file spans)
1346
+ pub fn collect_annotations (
1347
+ msp : & MultiSpan ,
1348
+ source_map : & Option < Lrc < SourceMapperDyn > >
1349
+ ) -> Vec < FileWithAnnotatedLines > {
1350
+ fn add_annotation_to_file ( file_vec : & mut Vec < FileWithAnnotatedLines > ,
1351
+ file : Lrc < SourceFile > ,
1352
+ line_index : usize ,
1353
+ ann : Annotation ) {
1354
+
1355
+ for slot in file_vec. iter_mut ( ) {
1356
+ // Look through each of our files for the one we're adding to
1357
+ if slot. file . name == file. name {
1358
+ // See if we already have a line for it
1359
+ for line_slot in & mut slot. lines {
1360
+ if line_slot. line_index == line_index {
1361
+ line_slot. annotations . push ( ann) ;
1362
+ return ;
1363
+ }
1364
+ }
1365
+ // We don't have a line yet, create one
1366
+ slot. lines . push ( Line {
1367
+ line_index,
1368
+ annotations : vec ! [ ann] ,
1369
+ } ) ;
1370
+ slot. lines . sort ( ) ;
1371
+ return ;
1372
+ }
1373
+ }
1374
+ // This is the first time we're seeing the file
1375
+ file_vec. push ( FileWithAnnotatedLines {
1376
+ file,
1377
+ lines : vec ! [ Line {
1378
+ line_index,
1379
+ annotations: vec![ ann] ,
1380
+ } ] ,
1381
+ multiline_depth : 0 ,
1382
+ } ) ;
1383
+ }
1384
+
1385
+ let mut output = vec ! [ ] ;
1386
+ let mut multiline_annotations = vec ! [ ] ;
1387
+
1388
+ if let Some ( ref sm) = source_map {
1389
+ for span_label in msp. span_labels ( ) {
1390
+ if span_label. span . is_dummy ( ) {
1391
+ continue ;
1392
+ }
1393
+
1394
+ let lo = sm. lookup_char_pos ( span_label. span . lo ( ) ) ;
1395
+ let mut hi = sm. lookup_char_pos ( span_label. span . hi ( ) ) ;
1396
+
1397
+ // Watch out for "empty spans". If we get a span like 6..6, we
1398
+ // want to just display a `^` at 6, so convert that to
1399
+ // 6..7. This is degenerate input, but it's best to degrade
1400
+ // gracefully -- and the parser likes to supply a span like
1401
+ // that for EOF, in particular.
1402
+
1403
+ if lo. col_display == hi. col_display && lo. line == hi. line {
1404
+ hi. col_display += 1 ;
1405
+ }
1406
+
1407
+ let ann_type = if lo. line != hi. line {
1408
+ let ml = MultilineAnnotation {
1409
+ depth : 1 ,
1410
+ line_start : lo. line ,
1411
+ line_end : hi. line ,
1412
+ start_col : lo. col_display ,
1413
+ end_col : hi. col_display ,
1414
+ is_primary : span_label. is_primary ,
1415
+ label : span_label. label . clone ( ) ,
1416
+ overlaps_exactly : false ,
1417
+ } ;
1418
+ multiline_annotations. push ( ( lo. file . clone ( ) , ml. clone ( ) ) ) ;
1419
+ AnnotationType :: Multiline ( ml)
1420
+ } else {
1421
+ AnnotationType :: Singleline
1422
+ } ;
1423
+ let ann = Annotation {
1424
+ start_col : lo. col_display ,
1425
+ end_col : hi. col_display ,
1426
+ is_primary : span_label. is_primary ,
1427
+ label : span_label. label . clone ( ) ,
1428
+ annotation_type : ann_type,
1429
+ } ;
1430
+
1431
+ if !ann. is_multiline ( ) {
1432
+ add_annotation_to_file ( & mut output, lo. file , lo. line , ann) ;
1433
+ }
1434
+ }
1435
+ }
1436
+
1437
+ // Find overlapping multiline annotations, put them at different depths
1438
+ multiline_annotations. sort_by_key ( |& ( _, ref ml) | ( ml. line_start , ml. line_end ) ) ;
1439
+ for item in multiline_annotations. clone ( ) {
1440
+ let ann = item. 1 ;
1441
+ for item in multiline_annotations. iter_mut ( ) {
1442
+ let ref mut a = item. 1 ;
1443
+ // Move all other multiline annotations overlapping with this one
1444
+ // one level to the right.
1445
+ if !( ann. same_span ( a) ) &&
1446
+ num_overlap ( ann. line_start , ann. line_end , a. line_start , a. line_end , true )
1447
+ {
1448
+ a. increase_depth ( ) ;
1449
+ } else if ann. same_span ( a) && & ann != a {
1450
+ a. overlaps_exactly = true ;
1451
+ } else {
1452
+ break ;
1453
+ }
1454
+ }
1455
+ }
1456
+
1457
+ let mut max_depth = 0 ; // max overlapping multiline spans
1458
+ for ( file, ann) in multiline_annotations {
1459
+ if ann. depth > max_depth {
1460
+ max_depth = ann. depth ;
1461
+ }
1462
+ let mut end_ann = ann. as_end ( ) ;
1463
+ if !ann. overlaps_exactly {
1464
+ // avoid output like
1465
+ //
1466
+ // | foo(
1467
+ // | _____^
1468
+ // | |_____|
1469
+ // | || bar,
1470
+ // | || );
1471
+ // | || ^
1472
+ // | ||______|
1473
+ // | |______foo
1474
+ // | baz
1475
+ //
1476
+ // and instead get
1477
+ //
1478
+ // | foo(
1479
+ // | _____^
1480
+ // | | bar,
1481
+ // | | );
1482
+ // | | ^
1483
+ // | | |
1484
+ // | |______foo
1485
+ // | baz
1486
+ add_annotation_to_file ( & mut output, file. clone ( ) , ann. line_start , ann. as_start ( ) ) ;
1487
+ // 4 is the minimum vertical length of a multiline span when presented: two lines
1488
+ // of code and two lines of underline. This is not true for the special case where
1489
+ // the beginning doesn't have an underline, but the current logic seems to be
1490
+ // working correctly.
1491
+ let middle = min ( ann. line_start + 4 , ann. line_end ) ;
1492
+ for line in ann. line_start + 1 ..middle {
1493
+ // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`).
1494
+ add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
1495
+ }
1496
+ if middle < ann. line_end - 1 {
1497
+ for line in ann. line_end - 1 ..ann. line_end {
1498
+ add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
1499
+ }
1500
+ }
1501
+ } else {
1502
+ end_ann. annotation_type = AnnotationType :: Singleline ;
1503
+ }
1504
+ add_annotation_to_file ( & mut output, file, ann. line_end , end_ann) ;
1505
+ }
1506
+ for file_vec in output. iter_mut ( ) {
1507
+ file_vec. multiline_depth = max_depth;
1508
+ }
1509
+ output
1510
+ }
1511
+ }
1512
+
1506
1513
fn draw_col_separator ( buffer : & mut StyledBuffer , line : usize , col : usize ) {
1507
1514
buffer. puts ( line, col, "| " , Style :: LineNumber ) ;
1508
1515
}
0 commit comments