@@ -179,6 +179,7 @@ pub struct EmitterWriter {
179
179
sm : Option < Lrc < SourceMapperDyn > > ,
180
180
short_message : bool ,
181
181
teach : bool ,
182
+ strip_margin : bool ,
182
183
ui_testing : bool ,
183
184
}
184
185
@@ -201,6 +202,7 @@ impl EmitterWriter {
201
202
sm : source_map,
202
203
short_message,
203
204
teach,
205
+ strip_margin : false ,
204
206
ui_testing : false ,
205
207
}
206
208
}
@@ -217,6 +219,7 @@ impl EmitterWriter {
217
219
sm : source_map,
218
220
short_message,
219
221
teach,
222
+ strip_margin : false ,
220
223
ui_testing : false ,
221
224
}
222
225
}
@@ -234,12 +237,29 @@ impl EmitterWriter {
234
237
}
235
238
}
236
239
237
- fn render_source_line ( & self ,
238
- buffer : & mut StyledBuffer ,
239
- file : Lrc < SourceFile > ,
240
- line : & Line ,
241
- width_offset : usize ,
242
- code_offset : usize ) -> Vec < ( usize , Style ) > {
240
+ fn render_source_line (
241
+ & self ,
242
+ buffer : & mut StyledBuffer ,
243
+ file : Lrc < SourceFile > ,
244
+ line : & Line ,
245
+ width_offset : usize ,
246
+ code_offset : usize ,
247
+ margin : usize ,
248
+ right_span_margin : usize
249
+ ) -> Vec < ( usize , Style ) > {
250
+ // Draw:
251
+ //
252
+ // LL | ... code ...
253
+ // | ^^-^ span label
254
+ // | |
255
+ // | secondary span label
256
+ //
257
+ // ^^ ^ ^^^ ^^^^ ^^^ we don't care about code too far to the right of a span, we trim it
258
+ // | | | |
259
+ // | | | actual code found in your source code and the spans we use to mark it
260
+ // | | when there's too much wasted space to the left, we trim it to focus where it matters
261
+ // | vertical divider between the column number and the code
262
+ // column number
243
263
if line. line_index == 0 {
244
264
return Vec :: new ( ) ;
245
265
}
@@ -251,12 +271,28 @@ impl EmitterWriter {
251
271
252
272
let line_offset = buffer. num_lines ( ) ;
253
273
254
- // First create the source line we will highlight.
255
- buffer. puts ( line_offset, code_offset, & source_string, Style :: Quotation ) ;
256
- buffer. puts ( line_offset,
257
- 0 ,
258
- & self . maybe_anonymized ( line. line_index ) ,
259
- Style :: LineNumber ) ;
274
+ let left_margin = std:: cmp:: min ( margin, source_string. len ( ) ) ;
275
+ let right_margin = if source_string. len ( ) > right_span_margin + 120 {
276
+ right_span_margin + 120
277
+ } else {
278
+ source_string. len ( )
279
+ } ;
280
+ // Create the source line we will highlight.
281
+ buffer. puts (
282
+ line_offset,
283
+ code_offset,
284
+ & source_string[ left_margin..right_margin] , // On long lines, we strip the source line
285
+ Style :: Quotation ,
286
+ ) ;
287
+ if margin > 0 { // We have stripped some code/whitespace from the beginning, make it clear.
288
+ buffer. puts ( line_offset, code_offset, "..." , Style :: LineNumber ) ;
289
+ }
290
+ if right_margin != source_string. len ( ) {
291
+ // We have stripped some code after the right-most span end, make it clear we did so.
292
+ let offset = code_offset + right_margin - left_margin;
293
+ buffer. puts ( line_offset, offset, "..." , Style :: LineNumber ) ;
294
+ }
295
+ buffer. puts ( line_offset, 0 , & self . maybe_anonymized ( line. line_index ) , Style :: LineNumber ) ;
260
296
261
297
draw_col_separator ( buffer, line_offset, width_offset - 2 ) ;
262
298
@@ -279,18 +315,13 @@ impl EmitterWriter {
279
315
if line. annotations . len ( ) == 1 {
280
316
if let Some ( ref ann) = line. annotations . get ( 0 ) {
281
317
if let AnnotationType :: MultilineStart ( depth) = ann. annotation_type {
282
- if source_string. chars ( )
283
- . take ( ann. start_col )
284
- . all ( |c| c. is_whitespace ( ) ) {
318
+ if source_string. chars ( ) . take ( ann. start_col ) . all ( |c| c. is_whitespace ( ) ) {
285
319
let style = if ann. is_primary {
286
320
Style :: UnderlinePrimary
287
321
} else {
288
322
Style :: UnderlineSecondary
289
323
} ;
290
- buffer. putc ( line_offset,
291
- width_offset + depth - 1 ,
292
- '/' ,
293
- style) ;
324
+ buffer. putc ( line_offset, width_offset + depth - 1 , '/' , style) ;
294
325
return vec ! [ ( depth, style) ] ;
295
326
}
296
327
}
@@ -515,13 +546,13 @@ impl EmitterWriter {
515
546
'_' ,
516
547
line_offset + pos,
517
548
width_offset + depth,
518
- code_offset + annotation. start_col ,
549
+ code_offset + annotation. start_col - margin ,
519
550
style) ;
520
551
}
521
552
_ if self . teach => {
522
553
buffer. set_style_range ( line_offset,
523
- code_offset + annotation. start_col ,
524
- code_offset + annotation. end_col ,
554
+ code_offset + annotation. start_col - margin ,
555
+ code_offset + annotation. end_col - margin ,
525
556
style,
526
557
annotation. is_primary ) ;
527
558
}
@@ -551,7 +582,7 @@ impl EmitterWriter {
551
582
if pos > 1 && ( annotation. has_label ( ) || annotation. takes_space ( ) ) {
552
583
for p in line_offset + 1 ..=line_offset + pos {
553
584
buffer. putc ( p,
554
- code_offset + annotation. start_col ,
585
+ code_offset + annotation. start_col - margin ,
555
586
'|' ,
556
587
style) ;
557
588
}
@@ -595,9 +626,9 @@ impl EmitterWriter {
595
626
Style :: LabelSecondary
596
627
} ;
597
628
let ( pos, col) = if pos == 0 {
598
- ( pos + 1 , annotation. end_col + 1 )
629
+ ( pos + 1 , annotation. end_col + 1 - margin )
599
630
} else {
600
- ( pos + 2 , annotation. start_col )
631
+ ( pos + 2 , annotation. start_col - margin )
601
632
} ;
602
633
if let Some ( ref label) = annotation. label {
603
634
buffer. puts ( line_offset + pos,
@@ -639,7 +670,7 @@ impl EmitterWriter {
639
670
} ;
640
671
for p in annotation. start_col ..annotation. end_col {
641
672
buffer. putc ( line_offset + 1 ,
642
- code_offset + p,
673
+ code_offset + p - margin ,
643
674
underline,
644
675
style) ;
645
676
}
@@ -1037,6 +1068,51 @@ impl EmitterWriter {
1037
1068
// Contains the vertical lines' positions for active multiline annotations
1038
1069
let mut multilines = FxHashMap :: default ( ) ;
1039
1070
1071
+ // Get the left-side margin to remove it
1072
+ let mut margin = std:: usize:: MAX ;
1073
+ for line_idx in 0 ..annotated_file. lines . len ( ) {
1074
+ let file = annotated_file. file . clone ( ) ;
1075
+ let line = & annotated_file. lines [ line_idx] ;
1076
+ if let Some ( source_string) = file. get_line ( line. line_index - 1 ) {
1077
+ let leading_whitespace = source_string
1078
+ . chars ( )
1079
+ . take_while ( |c| c. is_whitespace ( ) )
1080
+ . count ( ) ;
1081
+ if source_string. chars ( ) . any ( |c| !c. is_whitespace ( ) ) {
1082
+ margin = std:: cmp:: min ( margin, leading_whitespace) ;
1083
+ }
1084
+ }
1085
+ }
1086
+ if margin >= 20 { // On errors with generous margins, trim it
1087
+ margin = margin - 16 ; // Keep at least 4 spaces margin
1088
+ } else if margin == std:: usize:: MAX || !self . strip_margin {
1089
+ margin = 0 ;
1090
+ }
1091
+
1092
+ // Left-most column any visible span points at.
1093
+ let mut span_left_margin = std:: usize:: MAX ;
1094
+ for line in & annotated_file. lines {
1095
+ for ann in & line. annotations {
1096
+ span_left_margin = std:: cmp:: min ( span_left_margin, ann. start_col ) ;
1097
+ span_left_margin = std:: cmp:: min ( span_left_margin, ann. end_col ) ;
1098
+ }
1099
+ }
1100
+ if span_left_margin == std:: usize:: MAX {
1101
+ span_left_margin = 0 ;
1102
+ }
1103
+ if span_left_margin > 160 {
1104
+ margin = std:: cmp:: max ( margin, span_left_margin - 100 ) ;
1105
+ }
1106
+
1107
+ // Right-most column any visible span points at.
1108
+ let mut span_right_margin = 0 ;
1109
+ for line in & annotated_file. lines {
1110
+ for ann in & line. annotations {
1111
+ span_right_margin = std:: cmp:: max ( span_right_margin, ann. start_col ) ;
1112
+ span_right_margin = std:: cmp:: max ( span_right_margin, ann. end_col ) ;
1113
+ }
1114
+ }
1115
+
1040
1116
// Next, output the annotate source for this file
1041
1117
for line_idx in 0 ..annotated_file. lines . len ( ) {
1042
1118
let previous_buffer_line = buffer. num_lines ( ) ;
@@ -1048,11 +1124,15 @@ impl EmitterWriter {
1048
1124
width_offset + annotated_file. multiline_depth + 1
1049
1125
} ;
1050
1126
1051
- let depths = self . render_source_line ( & mut buffer,
1052
- annotated_file. file . clone ( ) ,
1053
- & annotated_file. lines [ line_idx] ,
1054
- width_offset,
1055
- code_offset) ;
1127
+ let depths = self . render_source_line (
1128
+ & mut buffer,
1129
+ annotated_file. file . clone ( ) ,
1130
+ & annotated_file. lines [ line_idx] ,
1131
+ width_offset,
1132
+ code_offset,
1133
+ margin,
1134
+ span_right_margin,
1135
+ ) ;
1056
1136
1057
1137
let mut to_add = FxHashMap :: default ( ) ;
1058
1138
@@ -1107,9 +1187,15 @@ impl EmitterWriter {
1107
1187
draw_col_separator ( & mut buffer,
1108
1188
last_buffer_line_num,
1109
1189
1 + max_line_num_len) ;
1190
+ let left_margin = std:: cmp:: min ( margin, unannotated_line. len ( ) ) ;
1191
+ let right_margin = if unannotated_line. len ( ) > span_right_margin + 120 {
1192
+ span_right_margin + 120
1193
+ } else {
1194
+ unannotated_line. len ( )
1195
+ } ;
1110
1196
buffer. puts ( last_buffer_line_num,
1111
1197
code_offset,
1112
- & unannotated_line,
1198
+ & unannotated_line[ left_margin..right_margin ] ,
1113
1199
Style :: Quotation ) ;
1114
1200
1115
1201
for ( depth, style) in & multilines {
0 commit comments