@@ -14,7 +14,7 @@ use syntax_pos::{COMMAND_LINE_SP, DUMMY_SP, FileMap, Span, MultiSpan, CharPos};
14
14
15
15
use { Level , CodeSuggestion , DiagnosticBuilder , SubDiagnostic , CodeMapper } ;
16
16
use RenderSpan :: * ;
17
- use snippet:: { StyledString , Style , Annotation , Line } ;
17
+ use snippet:: { Annotation , AnnotationType , Line , StyledString , Style } ;
18
18
use styled_buffer:: StyledBuffer ;
19
19
20
20
use std:: io:: prelude:: * ;
@@ -65,6 +65,7 @@ pub struct EmitterWriter {
65
65
struct FileWithAnnotatedLines {
66
66
file : Rc < FileMap > ,
67
67
lines : Vec < Line > ,
68
+ multiline_depth : usize ,
68
69
}
69
70
70
71
@@ -137,10 +138,12 @@ impl EmitterWriter {
137
138
line_index: line_index,
138
139
annotations: vec![ ann] ,
139
140
} ] ,
141
+ multiline_depth : 0 ,
140
142
} ) ;
141
143
}
142
144
143
145
let mut output = vec ! [ ] ;
146
+ let mut multiline_annotations = vec ! [ ] ;
144
147
145
148
if let Some ( ref cm) = self . cm {
146
149
for span_label in msp. span_labels ( ) {
@@ -151,8 +154,9 @@ impl EmitterWriter {
151
154
let mut hi = cm. lookup_char_pos ( span_label. span . hi ) ;
152
155
let mut is_minimized = false ;
153
156
154
- // If the span is multi-line, simplify down to the span of one character
155
- if lo. line != hi. line {
157
+ // If the span is long multi-line, simplify down to the span of one character
158
+ let max_multiline_span_length = 8 ;
159
+ if lo. line != hi. line && ( hi. line - lo. line ) > max_multiline_span_length {
156
160
hi. line = lo. line ;
157
161
hi. col = CharPos ( lo. col . 0 + 1 ) ;
158
162
is_minimized = true ;
@@ -163,37 +167,92 @@ impl EmitterWriter {
163
167
// 6..7. This is degenerate input, but it's best to degrade
164
168
// gracefully -- and the parser likes to supply a span like
165
169
// that for EOF, in particular.
166
- if lo. col == hi. col {
170
+ if lo. col == hi. col && lo . line == hi . line {
167
171
hi. col = CharPos ( lo. col . 0 + 1 ) ;
168
172
}
169
173
170
- add_annotation_to_file ( & mut output,
171
- lo. file ,
172
- lo. line ,
173
- Annotation {
174
- start_col : lo. col . 0 ,
175
- end_col : hi. col . 0 ,
176
- is_primary : span_label. is_primary ,
177
- is_minimized : is_minimized,
178
- label : span_label. label . clone ( ) ,
179
- } ) ;
174
+ let mut ann = Annotation {
175
+ start_col : lo. col . 0 ,
176
+ end_col : hi. col . 0 ,
177
+ is_primary : span_label. is_primary ,
178
+ label : span_label. label . clone ( ) ,
179
+ annotation_type : AnnotationType :: Singleline ,
180
+ } ;
181
+ if is_minimized {
182
+ ann. annotation_type = AnnotationType :: Minimized ;
183
+ } else if lo. line != hi. line {
184
+ ann. annotation_type = AnnotationType :: Multiline {
185
+ depth : 1 ,
186
+ line_start : lo. line ,
187
+ line_end : hi. line ,
188
+ } ;
189
+ multiline_annotations. push ( ( lo. file . clone ( ) , ann. clone ( ) ) ) ;
190
+ } ;
191
+
192
+ if !ann. is_multiline ( ) {
193
+ add_annotation_to_file ( & mut output,
194
+ lo. file ,
195
+ lo. line ,
196
+ ann) ;
197
+ }
198
+ }
199
+ }
200
+
201
+ // Find overlapping multiline annotations, put them at different depths
202
+ multiline_annotations. sort_by ( |a, b| a. 1 . start_col . cmp ( & b. 1 . start_col ) ) ;
203
+ for item in multiline_annotations. clone ( ) {
204
+ let ann = item. 1 ;
205
+ for item in multiline_annotations. iter_mut ( ) {
206
+ let ref mut a = item. 1 ;
207
+ let ann_depth = ann. annotation_type . depth ( ) ;
208
+ let a_depth = a. annotation_type . depth ( ) ;
209
+ // Move all other multiline annotations overlapping with this one
210
+ // one level to the right.
211
+ if & ann != a && ann. end_col > a. start_col && ann_depth == a_depth {
212
+ a. annotation_type . increase_depth ( ) ;
213
+ } else {
214
+ break
215
+ }
216
+ }
217
+ }
218
+
219
+ let mut max_depth = 0 ; // max overlapping multiline spans
220
+ for ( file, ann) in multiline_annotations {
221
+ if let AnnotationType :: Multiline { line_start, line_end, depth} = ann. annotation_type {
222
+ if depth > max_depth {
223
+ max_depth = depth;
224
+ }
225
+ add_annotation_to_file ( & mut output, file. clone ( ) , line_start, ann. as_start ( ) ) ;
226
+ for line in line_start + 1 ..line_end {
227
+ add_annotation_to_file ( & mut output, file. clone ( ) , line, ann. as_line ( ) ) ;
228
+ }
229
+ add_annotation_to_file ( & mut output, file, line_end, ann. as_end ( ) ) ;
180
230
}
181
231
}
232
+ for file_vec in output. iter_mut ( ) {
233
+ file_vec. multiline_depth = max_depth;
234
+ }
182
235
output
183
236
}
184
237
185
238
fn render_source_line ( & self ,
186
239
buffer : & mut StyledBuffer ,
187
240
file : Rc < FileMap > ,
188
241
line : & Line ,
189
- width_offset : usize ) {
242
+ width_offset : usize ,
243
+ multiline_depth : usize ) {
190
244
let source_string = file. get_line ( line. line_index - 1 )
191
245
. unwrap_or ( "" ) ;
192
246
193
247
let line_offset = buffer. num_lines ( ) ;
248
+ let code_offset = if multiline_depth == 0 {
249
+ width_offset
250
+ } else {
251
+ width_offset + multiline_depth + 1
252
+ } ;
194
253
195
254
// First create the source line we will highlight.
196
- buffer. puts ( line_offset, width_offset , & source_string, Style :: Quotation ) ;
255
+ buffer. puts ( line_offset, code_offset , & source_string, Style :: Quotation ) ;
197
256
buffer. puts ( line_offset,
198
257
0 ,
199
258
& ( line. line_index . to_string ( ) ) ,
@@ -228,39 +287,74 @@ impl EmitterWriter {
228
287
let mut annotations = line. annotations . clone ( ) ;
229
288
annotations. sort ( ) ;
230
289
290
+ let mut only_source_shown = true ;
231
291
// Next, create the highlight line.
232
292
for annotation in & annotations {
293
+ let ( underline, style) = if annotation. is_primary {
294
+ ( '^' , Style :: UnderlinePrimary )
295
+ } else {
296
+ ( '-' , Style :: UnderlineSecondary )
297
+ } ;
298
+ if let AnnotationType :: MultilineLine ( depth) = annotation. annotation_type {
299
+ draw_col_separator_no_space_with_style ( buffer,
300
+ line_offset,
301
+ width_offset + depth - 1 ,
302
+ style) ;
303
+ break ;
304
+ }
233
305
for p in annotation. start_col ..annotation. end_col {
234
- if annotation. is_primary {
235
- buffer. putc ( line_offset + 1 ,
236
- width_offset + p,
237
- '^' ,
238
- Style :: UnderlinePrimary ) ;
239
- if !annotation. is_minimized {
240
- buffer. set_style ( line_offset, width_offset + p, Style :: UnderlinePrimary ) ;
241
- }
242
- } else {
306
+ buffer. putc ( line_offset + 1 ,
307
+ code_offset + p,
308
+ underline,
309
+ style) ;
310
+ if !annotation. is_minimized ( ) {
311
+ buffer. set_style ( line_offset, code_offset + p, style) ;
312
+ }
313
+ }
314
+ // For multiline spans, add enclosing line
315
+ if let AnnotationType :: MultilineStart ( depth) = annotation. annotation_type {
316
+ for p in width_offset + depth..code_offset + annotation. end_col - 1 {
243
317
buffer. putc ( line_offset + 1 ,
244
- width_offset + p,
245
- '-' ,
246
- Style :: UnderlineSecondary ) ;
247
- if !annotation. is_minimized {
248
- buffer. set_style ( line_offset, width_offset + p, Style :: UnderlineSecondary ) ;
249
- }
318
+ p,
319
+ '_' ,
320
+ style) ;
250
321
}
251
322
}
323
+ if let AnnotationType :: MultilineEnd ( depth) = annotation. annotation_type {
324
+ draw_col_separator_no_space_with_style ( buffer,
325
+ line_offset,
326
+ width_offset + depth - 1 ,
327
+ style) ;
328
+ draw_col_separator_no_space_with_style ( buffer,
329
+ line_offset + 1 ,
330
+ width_offset + depth - 1 ,
331
+ style) ;
332
+ draw_range ( buffer,
333
+ '_' ,
334
+ line_offset + 1 ,
335
+ width_offset + depth,
336
+ code_offset + annotation. end_col - 1 ,
337
+ style) ;
338
+ }
339
+ only_source_shown = false ;
340
+ }
341
+ if !only_source_shown {
342
+ draw_col_separator ( buffer, line_offset + 1 , width_offset - 2 ) ;
252
343
}
253
- draw_col_separator ( buffer, line_offset + 1 , width_offset - 2 ) ;
254
344
255
345
// Now we are going to write labels in. To start, we'll exclude
256
346
// the annotations with no labels.
257
- let ( labeled_annotations, unlabeled_annotations) : ( Vec < _ > , _ ) = annotations. into_iter ( )
258
- . partition ( |a| a. label . is_some ( ) ) ;
347
+ let ( labeled_annotations, unlabeled_annotations) : ( Vec < _ > , _ ) = annotations
348
+ . clone ( ) . into_iter ( ) . partition ( |a| a. label . is_some ( ) ) ;
259
349
260
350
// If there are no annotations that need text, we're done.
261
351
if labeled_annotations. is_empty ( ) {
262
352
return ;
263
353
}
354
+
355
+ let multiline_annotations = annotations. iter ( )
356
+ . filter ( |a| a. is_multiline ( ) ) . collect :: < Vec < _ > > ( ) ;
357
+
264
358
// Now add the text labels. We try, when possible, to stick the rightmost
265
359
// annotation at the end of the highlight line:
266
360
//
@@ -305,11 +399,11 @@ impl EmitterWriter {
305
399
// append the label afterwards; we keep it in a separate
306
400
// string
307
401
let highlight_label: String = format ! ( " {}" , last. label. as_ref( ) . unwrap( ) ) ;
308
- if last. is_primary {
309
- buffer . append ( line_offset + 1 , & highlight_label , Style :: LabelPrimary ) ;
402
+ buffer . append ( line_offset + 1 , & highlight_label , if last. is_primary {
403
+ Style :: LabelPrimary
310
404
} else {
311
- buffer . append ( line_offset + 1 , & highlight_label , Style :: LabelSecondary ) ;
312
- }
405
+ Style :: LabelSecondary
406
+ } ) ;
313
407
labeled_annotations = previous;
314
408
}
315
409
}
@@ -330,28 +424,35 @@ impl EmitterWriter {
330
424
// For each blank line, draw a `|` at our column. The
331
425
// text ought to be long enough for this.
332
426
for index in 2 ..blank_lines {
333
- if annotation. is_primary {
334
- buffer. putc ( line_offset + index,
335
- width_offset + annotation. start_col ,
336
- '|' ,
337
- Style :: UnderlinePrimary ) ;
427
+ let style = if annotation. is_primary {
428
+ Style :: UnderlinePrimary
338
429
} else {
339
- buffer. putc ( line_offset + index,
340
- width_offset + annotation. start_col ,
341
- '|' ,
342
- Style :: UnderlineSecondary ) ;
430
+ Style :: UnderlineSecondary
431
+ } ;
432
+ draw_col_separator_no_space_with_style ( buffer,
433
+ line_offset + index,
434
+ code_offset + annotation. start_col ,
435
+ style) ;
436
+ for a in multiline_annotations. iter ( ) {
437
+ if let AnnotationType :: MultilineLine ( depth) = a. annotation_type {
438
+ draw_col_separator_no_space_with_style ( buffer,
439
+ line_offset + index,
440
+ width_offset + depth - 1 ,
441
+ style) ;
442
+ }
343
443
}
344
444
draw_col_separator ( buffer, line_offset + index, width_offset - 2 ) ;
445
+
345
446
}
346
447
347
448
if annotation. is_primary {
348
449
buffer. puts ( line_offset + blank_lines,
349
- width_offset + annotation. start_col ,
450
+ code_offset + annotation. start_col ,
350
451
annotation. label . as_ref ( ) . unwrap ( ) ,
351
452
Style :: LabelPrimary ) ;
352
453
} else {
353
454
buffer. puts ( line_offset + blank_lines,
354
- width_offset + annotation. start_col ,
455
+ code_offset + annotation. start_col ,
355
456
annotation. label . as_ref ( ) . unwrap ( ) ,
356
457
Style :: LabelSecondary ) ;
357
458
}
@@ -577,7 +678,8 @@ impl EmitterWriter {
577
678
self . render_source_line ( & mut buffer,
578
679
annotated_file. file . clone ( ) ,
579
680
& annotated_file. lines [ line_idx] ,
580
- 3 + max_line_num_len) ;
681
+ 3 + max_line_num_len,
682
+ annotated_file. multiline_depth ) ;
581
683
582
684
// check to see if we need to print out or elide lines that come between
583
685
// this annotated line and the next one
@@ -729,7 +831,19 @@ fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
729
831
}
730
832
731
833
fn draw_col_separator_no_space ( buffer : & mut StyledBuffer , line : usize , col : usize ) {
732
- buffer. puts ( line, col, "|" , Style :: LineNumber ) ;
834
+ draw_col_separator_no_space_with_style ( buffer, line, col, Style :: LineNumber ) ;
835
+ }
836
+
837
+ fn draw_col_separator_no_space_with_style ( buffer : & mut StyledBuffer , line : usize ,
838
+ col : usize , style : Style ) {
839
+ buffer. putc ( line, col, '|' , style) ;
840
+ }
841
+
842
+ fn draw_range ( buffer : & mut StyledBuffer , symbol : char , line : usize ,
843
+ col_from : usize , col_to : usize , style : Style ) {
844
+ for col in col_from..col_to {
845
+ buffer. putc ( line, col, symbol, style) ;
846
+ }
733
847
}
734
848
735
849
fn draw_note_separator ( buffer : & mut StyledBuffer , line : usize , col : usize ) {
0 commit comments