@@ -179,6 +179,7 @@ pub struct EmitterWriter {
179179 sm : Option < Lrc < SourceMapperDyn > > ,
180180 short_message : bool ,
181181 teach : bool ,
182+ strip_margin : bool ,
182183 ui_testing : bool ,
183184}
184185
@@ -201,6 +202,7 @@ impl EmitterWriter {
201202 sm : source_map,
202203 short_message,
203204 teach,
205+ strip_margin : false ,
204206 ui_testing : false ,
205207 }
206208 }
@@ -217,6 +219,7 @@ impl EmitterWriter {
217219 sm : source_map,
218220 short_message,
219221 teach,
222+ strip_margin : false ,
220223 ui_testing : false ,
221224 }
222225 }
@@ -234,12 +237,29 @@ impl EmitterWriter {
234237 }
235238 }
236239
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
243263 if line. line_index == 0 {
244264 return Vec :: new ( ) ;
245265 }
@@ -251,12 +271,28 @@ impl EmitterWriter {
251271
252272 let line_offset = buffer. num_lines ( ) ;
253273
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 ) ;
260296
261297 draw_col_separator ( buffer, line_offset, width_offset - 2 ) ;
262298
@@ -279,18 +315,13 @@ impl EmitterWriter {
279315 if line. annotations . len ( ) == 1 {
280316 if let Some ( ref ann) = line. annotations . get ( 0 ) {
281317 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 ( ) ) {
285319 let style = if ann. is_primary {
286320 Style :: UnderlinePrimary
287321 } else {
288322 Style :: UnderlineSecondary
289323 } ;
290- buffer. putc ( line_offset,
291- width_offset + depth - 1 ,
292- '/' ,
293- style) ;
324+ buffer. putc ( line_offset, width_offset + depth - 1 , '/' , style) ;
294325 return vec ! [ ( depth, style) ] ;
295326 }
296327 }
@@ -515,13 +546,13 @@ impl EmitterWriter {
515546 '_' ,
516547 line_offset + pos,
517548 width_offset + depth,
518- code_offset + annotation. start_col ,
549+ code_offset + annotation. start_col - margin ,
519550 style) ;
520551 }
521552 _ if self . teach => {
522553 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 ,
525556 style,
526557 annotation. is_primary ) ;
527558 }
@@ -551,7 +582,7 @@ impl EmitterWriter {
551582 if pos > 1 && ( annotation. has_label ( ) || annotation. takes_space ( ) ) {
552583 for p in line_offset + 1 ..=line_offset + pos {
553584 buffer. putc ( p,
554- code_offset + annotation. start_col ,
585+ code_offset + annotation. start_col - margin ,
555586 '|' ,
556587 style) ;
557588 }
@@ -595,9 +626,9 @@ impl EmitterWriter {
595626 Style :: LabelSecondary
596627 } ;
597628 let ( pos, col) = if pos == 0 {
598- ( pos + 1 , annotation. end_col + 1 )
629+ ( pos + 1 , annotation. end_col + 1 - margin )
599630 } else {
600- ( pos + 2 , annotation. start_col )
631+ ( pos + 2 , annotation. start_col - margin )
601632 } ;
602633 if let Some ( ref label) = annotation. label {
603634 buffer. puts ( line_offset + pos,
@@ -639,7 +670,7 @@ impl EmitterWriter {
639670 } ;
640671 for p in annotation. start_col ..annotation. end_col {
641672 buffer. putc ( line_offset + 1 ,
642- code_offset + p,
673+ code_offset + p - margin ,
643674 underline,
644675 style) ;
645676 }
@@ -1037,6 +1068,51 @@ impl EmitterWriter {
10371068 // Contains the vertical lines' positions for active multiline annotations
10381069 let mut multilines = FxHashMap :: default ( ) ;
10391070
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+
10401116 // Next, output the annotate source for this file
10411117 for line_idx in 0 ..annotated_file. lines . len ( ) {
10421118 let previous_buffer_line = buffer. num_lines ( ) ;
@@ -1048,11 +1124,15 @@ impl EmitterWriter {
10481124 width_offset + annotated_file. multiline_depth + 1
10491125 } ;
10501126
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+ ) ;
10561136
10571137 let mut to_add = FxHashMap :: default ( ) ;
10581138
@@ -1107,9 +1187,15 @@ impl EmitterWriter {
11071187 draw_col_separator ( & mut buffer,
11081188 last_buffer_line_num,
11091189 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+ } ;
11101196 buffer. puts ( last_buffer_line_num,
11111197 code_offset,
1112- & unannotated_line,
1198+ & unannotated_line[ left_margin..right_margin ] ,
11131199 Style :: Quotation ) ;
11141200
11151201 for ( depth, style) in & multilines {
0 commit comments