@@ -162,6 +162,7 @@ impl ColorConfig {
162162 }
163163}
164164
165+ /// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
165166pub struct EmitterWriter {
166167 dst : Destination ,
167168 sm : Option < Lrc < SourceMapperDyn > > ,
@@ -170,7 +171,8 @@ pub struct EmitterWriter {
170171 ui_testing : bool ,
171172}
172173
173- struct FileWithAnnotatedLines {
174+ #[ derive( Debug ) ]
175+ pub struct FileWithAnnotatedLines {
174176 file : Lrc < SourceFile > ,
175177 lines : Vec < Line > ,
176178 multiline_depth : usize ,
@@ -221,169 +223,6 @@ impl EmitterWriter {
221223 }
222224 }
223225
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-
387226 fn render_source_line ( & self ,
388227 buffer : & mut StyledBuffer ,
389228 file : Lrc < SourceFile > ,
@@ -1093,9 +932,7 @@ impl EmitterWriter {
1093932 }
1094933 }
1095934
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 ) ;
1099936
1100937 // Make sure our primary file comes first
1101938 let ( primary_lo, sm) = if let ( Some ( sm) , Some ( ref primary_span) ) =
@@ -1503,6 +1340,176 @@ impl EmitterWriter {
15031340 }
15041341}
15051342
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+
15061513fn draw_col_separator ( buffer : & mut StyledBuffer , line : usize , col : usize ) {
15071514 buffer. puts ( line, col, "| " , Style :: LineNumber ) ;
15081515}
0 commit comments