@@ -21,6 +21,8 @@ use std::io::prelude::*;
21
21
use std:: io;
22
22
use std:: rc:: Rc ;
23
23
use term;
24
+ use std:: collections:: HashMap ;
25
+ use std:: cmp:: min;
24
26
25
27
/// Emitter trait for emitting errors.
26
28
pub trait Emitter {
@@ -156,15 +158,6 @@ impl EmitterWriter {
156
158
}
157
159
let lo = cm. lookup_char_pos ( span_label. span . lo ) ;
158
160
let mut hi = cm. lookup_char_pos ( span_label. span . hi ) ;
159
- let mut is_minimized = false ;
160
-
161
- // If the span is long multi-line, simplify down to the span of one character
162
- let max_multiline_span_length = 8 ;
163
- if lo. line != hi. line && ( hi. line - lo. line ) > max_multiline_span_length {
164
- hi. line = lo. line ;
165
- hi. col = CharPos ( lo. col . 0 + 1 ) ;
166
- is_minimized = true ;
167
- }
168
161
169
162
// Watch out for "empty spans". If we get a span like 6..6, we
170
163
// want to just display a `^` at 6, so convert that to
@@ -175,16 +168,7 @@ impl EmitterWriter {
175
168
hi. col = CharPos ( lo. col . 0 + 1 ) ;
176
169
}
177
170
178
- let mut ann = Annotation {
179
- start_col : lo. col . 0 ,
180
- end_col : hi. col . 0 ,
181
- is_primary : span_label. is_primary ,
182
- label : span_label. label . clone ( ) ,
183
- annotation_type : AnnotationType :: Singleline ,
184
- } ;
185
- if is_minimized {
186
- ann. annotation_type = AnnotationType :: Minimized ;
187
- } else if lo. line != hi. line {
171
+ let ann_type = if lo. line != hi. line {
188
172
let ml = MultilineAnnotation {
189
173
depth : 1 ,
190
174
line_start : lo. line ,
@@ -194,8 +178,17 @@ impl EmitterWriter {
194
178
is_primary : span_label. is_primary ,
195
179
label : span_label. label . clone ( ) ,
196
180
} ;
197
- ann. annotation_type = AnnotationType :: Multiline ( ml. clone ( ) ) ;
198
- multiline_annotations. push ( ( lo. file . clone ( ) , ml) ) ;
181
+ multiline_annotations. push ( ( lo. file . clone ( ) , ml. clone ( ) ) ) ;
182
+ AnnotationType :: Multiline ( ml)
183
+ } else {
184
+ AnnotationType :: Singleline
185
+ } ;
186
+ let ann = Annotation {
187
+ start_col : lo. col . 0 ,
188
+ end_col : hi. col . 0 ,
189
+ is_primary : span_label. is_primary ,
190
+ label : span_label. label . clone ( ) ,
191
+ annotation_type : ann_type,
199
192
} ;
200
193
201
194
if !ann. is_multiline ( ) {
@@ -233,9 +226,15 @@ impl EmitterWriter {
233
226
max_depth = ann. depth ;
234
227
}
235
228
add_annotation_to_file ( & mut output, file. clone ( ) , ann. line_start , ann. as_start ( ) ) ;
236
- for line in ann. line_start + 1 ..ann. line_end {
229
+ let middle = min ( ann. line_start + 4 , ann. line_end ) ;
230
+ for line in ann. line_start + 1 ..middle {
237
231
add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
238
232
}
233
+ if middle < ann. line_end - 1 {
234
+ for line in ann. line_end - 1 ..ann. line_end {
235
+ add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
236
+ }
237
+ }
239
238
add_annotation_to_file ( & mut output, file, ann. line_end , ann. as_end ( ) ) ;
240
239
}
241
240
for file_vec in output. iter_mut ( ) {
@@ -249,16 +248,11 @@ impl EmitterWriter {
249
248
file : Rc < FileMap > ,
250
249
line : & Line ,
251
250
width_offset : usize ,
252
- multiline_depth : usize ) {
251
+ code_offset : usize ) -> Vec < ( usize , Style ) > {
253
252
let source_string = file. get_line ( line. line_index - 1 )
254
253
. unwrap_or ( "" ) ;
255
254
256
255
let line_offset = buffer. num_lines ( ) ;
257
- let code_offset = if multiline_depth == 0 {
258
- width_offset
259
- } else {
260
- width_offset + multiline_depth + 1
261
- } ;
262
256
263
257
// First create the source line we will highlight.
264
258
buffer. puts ( line_offset, code_offset, & source_string, Style :: Quotation ) ;
@@ -286,7 +280,7 @@ impl EmitterWriter {
286
280
// previous borrow of `vec` occurs here
287
281
//
288
282
// For this reason, we group the lines into "highlight lines"
289
- // and "annotations lines", where the highlight lines have the `~ `.
283
+ // and "annotations lines", where the highlight lines have the `^ `.
290
284
291
285
// Sort the annotations by (start, end col)
292
286
let mut annotations = line. annotations . clone ( ) ;
@@ -410,25 +404,9 @@ impl EmitterWriter {
410
404
// If there are no annotations or the only annotations on this line are
411
405
// MultilineLine, then there's only code being shown, stop processing.
412
406
if line. annotations . is_empty ( ) || line. annotations . iter ( )
413
- . filter ( |a| {
414
- // Set the multiline annotation vertical lines to the left of
415
- // the code in this line.
416
- if let AnnotationType :: MultilineLine ( depth) = a. annotation_type {
417
- buffer. putc ( line_offset,
418
- width_offset + depth - 1 ,
419
- '|' ,
420
- if a. is_primary {
421
- Style :: UnderlinePrimary
422
- } else {
423
- Style :: UnderlineSecondary
424
- } ) ;
425
- false
426
- } else {
427
- true
428
- }
429
- } ) . collect :: < Vec < _ > > ( ) . len ( ) == 0
407
+ . filter ( |a| !a. is_line ( ) ) . collect :: < Vec < _ > > ( ) . len ( ) == 0
430
408
{
431
- return ;
409
+ return vec ! [ ] ;
432
410
}
433
411
434
412
// Write the colunmn separator.
@@ -483,16 +461,15 @@ impl EmitterWriter {
483
461
}
484
462
}
485
463
486
- // Write the vertical lines for multiline spans and for labels that are
487
- // on a different line as the underline.
464
+ // Write the vertical lines for labels that are on a different line as the underline.
488
465
//
489
466
// After this we will have:
490
467
//
491
468
// 2 | fn foo() {
492
469
// | __________
493
470
// | | |
494
471
// | |
495
- // 3 | |
472
+ // 3 |
496
473
// 4 | | }
497
474
// | |_
498
475
for & ( pos, annotation) in & annotations_position {
@@ -528,16 +505,6 @@ impl EmitterWriter {
528
505
style) ;
529
506
}
530
507
}
531
- AnnotationType :: MultilineLine ( depth) => {
532
- // the first line will have already be filled when we checked
533
- // wether there were any annotations for this line.
534
- for p in line_offset + 1 ..line_offset + line_len + 2 {
535
- buffer. putc ( p,
536
- width_offset + depth - 1 ,
537
- '|' ,
538
- style) ;
539
- }
540
- }
541
508
_ => ( ) ,
542
509
}
543
510
}
@@ -548,11 +515,11 @@ impl EmitterWriter {
548
515
//
549
516
// 2 | fn foo() {
550
517
// | __________ starting here...
551
- // | | |
552
- // | | something about `foo`
553
- // 3 | |
554
- // 4 | | }
555
- // | | _ ...ending here: test
518
+ // | |
519
+ // | something about `foo`
520
+ // 3 |
521
+ // 4 | }
522
+ // | _ ...ending here: test
556
523
for & ( pos, annotation) in & annotations_position {
557
524
let style = if annotation. is_primary {
558
525
Style :: LabelPrimary
@@ -591,11 +558,11 @@ impl EmitterWriter {
591
558
//
592
559
// 2 | fn foo() {
593
560
// | ____-_____^ starting here...
594
- // | | |
595
- // | | something about `foo`
596
- // 3 | |
597
- // 4 | | }
598
- // | | _^ ...ending here: test
561
+ // | |
562
+ // | something about `foo`
563
+ // 3 |
564
+ // 4 | }
565
+ // | _^ ...ending here: test
599
566
for & ( _, annotation) in & annotations_position {
600
567
let ( underline, style) = if annotation. is_primary {
601
568
( '^' , Style :: UnderlinePrimary )
@@ -609,6 +576,20 @@ impl EmitterWriter {
609
576
style) ;
610
577
}
611
578
}
579
+ annotations_position. iter ( ) . filter_map ( |& ( _, annotation) | {
580
+ match annotation. annotation_type {
581
+ AnnotationType :: MultilineStart ( p) | AnnotationType :: MultilineEnd ( p) => {
582
+ let style = if annotation. is_primary {
583
+ Style :: LabelPrimary
584
+ } else {
585
+ Style :: LabelSecondary
586
+ } ;
587
+ Some ( ( p, style) )
588
+ } ,
589
+ _ => None
590
+ }
591
+
592
+ } ) . collect :: < Vec < _ > > ( )
612
593
}
613
594
614
595
fn get_multispan_max_line_num ( & mut self , msp : & MultiSpan ) -> usize {
@@ -902,22 +883,64 @@ impl EmitterWriter {
902
883
let buffer_msg_line_offset = buffer. num_lines ( ) ;
903
884
draw_col_separator_no_space ( & mut buffer, buffer_msg_line_offset, max_line_num_len + 1 ) ;
904
885
886
+ // Contains the vertical lines' positions for active multiline annotations
887
+ let mut multilines = HashMap :: new ( ) ;
888
+
905
889
// Next, output the annotate source for this file
906
890
for line_idx in 0 ..annotated_file. lines . len ( ) {
907
- self . render_source_line ( & mut buffer,
908
- annotated_file. file . clone ( ) ,
909
- & annotated_file. lines [ line_idx] ,
910
- 3 + max_line_num_len,
911
- annotated_file. multiline_depth ) ;
891
+ let previous_buffer_line = buffer. num_lines ( ) ;
892
+
893
+ let width_offset = 3 + max_line_num_len;
894
+ let code_offset = if annotated_file. multiline_depth == 0 {
895
+ width_offset
896
+ } else {
897
+ width_offset + annotated_file. multiline_depth + 1
898
+ } ;
899
+
900
+ let depths = self . render_source_line ( & mut buffer,
901
+ annotated_file. file . clone ( ) ,
902
+ & annotated_file. lines [ line_idx] ,
903
+ width_offset,
904
+ code_offset) ;
912
905
906
+ let mut to_add = HashMap :: new ( ) ;
907
+
908
+ for ( depth, style) in depths {
909
+ if multilines. get ( & depth) . is_some ( ) {
910
+ multilines. remove ( & depth) ;
911
+ } else {
912
+ to_add. insert ( depth, style) ;
913
+ }
914
+ }
915
+
916
+ // Set the multiline annotation vertical lines to the left of
917
+ // the code in this line.
918
+ for ( depth, style) in & multilines {
919
+ for line in previous_buffer_line..buffer. num_lines ( ) {
920
+ draw_multiline_line ( & mut buffer,
921
+ line,
922
+ width_offset,
923
+ * depth,
924
+ * style) ;
925
+ }
926
+ }
913
927
// check to see if we need to print out or elide lines that come between
914
- // this annotated line and the next one
928
+ // this annotated line and the next one.
915
929
if line_idx < ( annotated_file. lines . len ( ) - 1 ) {
916
930
let line_idx_delta = annotated_file. lines [ line_idx + 1 ] . line_index -
917
931
annotated_file. lines [ line_idx] . line_index ;
918
932
if line_idx_delta > 2 {
919
933
let last_buffer_line_num = buffer. num_lines ( ) ;
920
934
buffer. puts ( last_buffer_line_num, 0 , "..." , Style :: LineNumber ) ;
935
+
936
+ // Set the multiline annotation vertical lines on `...` bridging line.
937
+ for ( depth, style) in & multilines {
938
+ draw_multiline_line ( & mut buffer,
939
+ last_buffer_line_num,
940
+ width_offset,
941
+ * depth,
942
+ * style) ;
943
+ }
921
944
} else if line_idx_delta == 2 {
922
945
let unannotated_line = annotated_file. file
923
946
. get_line ( annotated_file. lines [ line_idx] . line_index )
@@ -932,11 +955,21 @@ impl EmitterWriter {
932
955
Style :: LineNumber ) ;
933
956
draw_col_separator ( & mut buffer, last_buffer_line_num, 1 + max_line_num_len) ;
934
957
buffer. puts ( last_buffer_line_num,
935
- 3 + max_line_num_len ,
958
+ code_offset ,
936
959
& unannotated_line,
937
960
Style :: Quotation ) ;
961
+
962
+ for ( depth, style) in & multilines {
963
+ draw_multiline_line ( & mut buffer,
964
+ last_buffer_line_num,
965
+ width_offset,
966
+ * depth,
967
+ * style) ;
968
+ }
938
969
}
939
970
}
971
+
972
+ multilines. extend ( & to_add) ;
940
973
}
941
974
}
942
975
@@ -1085,6 +1118,15 @@ fn draw_note_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
1085
1118
buffer. puts ( line, col, "= " , Style :: LineNumber ) ;
1086
1119
}
1087
1120
1121
+ fn draw_multiline_line ( buffer : & mut StyledBuffer ,
1122
+ line : usize ,
1123
+ offset : usize ,
1124
+ depth : usize ,
1125
+ style : Style )
1126
+ {
1127
+ buffer. putc ( line, offset + depth - 1 , '|' , style) ;
1128
+ }
1129
+
1088
1130
fn num_overlap ( a_start : usize , a_end : usize , b_start : usize , b_end : usize , inclusive : bool ) -> bool {
1089
1131
let extra = if inclusive {
1090
1132
1
0 commit comments