@@ -113,24 +113,11 @@ impl Margin {
113
113
self . computed_left > 0
114
114
}
115
115
116
- fn was_cut_right ( & self , line_len : usize ) -> bool {
117
- let right =
118
- if self . computed_right == self . span_right || self . computed_right == self . label_right {
119
- // FIXME: This comment refers to the only callsite of this method.
120
- // Rephrase it or refactor it, so it can stand on its own.
121
- // Account for the "..." padding given above. Otherwise we end up with code lines
122
- // that do fit but end in "..." as if they were trimmed.
123
- // FIXME: Don't hard-code this offset. Is this meant to represent
124
- // `2 * str_width(self.margin())`?
125
- self . computed_right - 6
126
- } else {
127
- self . computed_right
128
- } ;
129
- right < line_len && self . computed_left + self . column_width < line_len
130
- }
131
-
132
116
fn compute ( & mut self , max_line_len : usize ) {
133
117
// When there's a lot of whitespace (>20), we want to trim it as it is useless.
118
+ // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that
119
+ // calculation later, right before printing in order to be accurate with both unicode
120
+ // handling and trimming of long lines.
134
121
self . computed_left = if self . whitespace_left > 20 {
135
122
self . whitespace_left - 16 // We want some padding.
136
123
} else {
@@ -668,43 +655,43 @@ impl HumanEmitter {
668
655
width_offset : usize ,
669
656
code_offset : usize ,
670
657
margin : Margin ,
671
- ) {
672
- // Tabs are assumed to have been replaced by spaces in calling code.
673
- debug_assert ! ( !source_string. contains( '\t' ) ) ;
658
+ ) -> usize {
674
659
let line_len = source_string. len ( ) ;
675
660
// Create the source line we will highlight.
676
661
let left = margin. left ( line_len) ;
677
662
let right = margin. right ( line_len) ;
678
663
// FIXME: The following code looks fishy. See #132860.
679
664
// On long lines, we strip the source line, accounting for unicode.
680
- let mut taken = 0 ;
681
665
let code: String = source_string
682
666
. chars ( )
683
- . skip ( left)
684
- . take_while ( |ch| {
685
- // Make sure that the trimming on the right will fall within the terminal width.
686
- let next = char_width ( * ch) ;
687
- if taken + next > right - left {
688
- return false ;
689
- }
690
- taken += next;
691
- true
692
- } )
667
+ . enumerate ( )
668
+ . skip_while ( |( i, _) | * i < left)
669
+ . take_while ( |( i, _) | * i < right)
670
+ . map ( |( _, c) | c)
693
671
. collect ( ) ;
672
+ let code = normalize_whitespace ( & code) ;
673
+ let was_cut_right =
674
+ source_string. chars ( ) . enumerate ( ) . skip_while ( |( i, _) | * i < right) . next ( ) . is_some ( ) ;
694
675
buffer. puts ( line_offset, code_offset, & code, Style :: Quotation ) ;
695
676
let placeholder = self . margin ( ) ;
696
677
if margin. was_cut_left ( ) {
697
678
// We have stripped some code/whitespace from the beginning, make it clear.
698
679
buffer. puts ( line_offset, code_offset, placeholder, Style :: LineNumber ) ;
699
680
}
700
- if margin . was_cut_right ( line_len ) {
681
+ if was_cut_right {
701
682
let padding = str_width ( placeholder) ;
702
683
// We have stripped some code after the rightmost span end, make it clear we did so.
703
- buffer. puts ( line_offset, code_offset + taken - padding, placeholder, Style :: LineNumber ) ;
684
+ buffer. puts (
685
+ line_offset,
686
+ code_offset + str_width ( & code) - padding,
687
+ placeholder,
688
+ Style :: LineNumber ,
689
+ ) ;
704
690
}
705
691
buffer. puts ( line_offset, 0 , & self . maybe_anonymized ( line_index) , Style :: LineNumber ) ;
706
692
707
693
self . draw_col_separator_no_space ( buffer, line_offset, width_offset - 2 ) ;
694
+ left
708
695
}
709
696
710
697
#[ instrument( level = "trace" , skip( self ) , ret) ]
@@ -736,22 +723,16 @@ impl HumanEmitter {
736
723
return Vec :: new ( ) ;
737
724
}
738
725
739
- let source_string = match file. get_line ( line. line_index - 1 ) {
740
- Some ( s) => normalize_whitespace ( & s) ,
741
- None => return Vec :: new ( ) ,
726
+ let Some ( source_string) = file. get_line ( line. line_index - 1 ) else {
727
+ return Vec :: new ( ) ;
742
728
} ;
743
729
trace ! ( ?source_string) ;
744
730
745
731
let line_offset = buffer. num_lines ( ) ;
746
732
747
- // Left trim
748
- let left = margin. left ( source_string. len ( ) ) ;
749
-
733
+ // Left trim.
750
734
// FIXME: This looks fishy. See #132860.
751
- // Account for unicode characters of width !=0 that were removed.
752
- let left = source_string. chars ( ) . take ( left) . map ( |ch| char_width ( ch) ) . sum ( ) ;
753
-
754
- self . draw_line (
735
+ let left = self . draw_line (
755
736
buffer,
756
737
& source_string,
757
738
line. line_index ,
@@ -1033,12 +1014,18 @@ impl HumanEmitter {
1033
1014
let pos = pos + 1 ;
1034
1015
match annotation. annotation_type {
1035
1016
AnnotationType :: MultilineStart ( depth) | AnnotationType :: MultilineEnd ( depth) => {
1017
+ let pre: usize = source_string
1018
+ . chars ( )
1019
+ . take ( annotation. start_col . file )
1020
+ . skip ( left)
1021
+ . map ( |c| char_width ( c) )
1022
+ . sum ( ) ;
1036
1023
self . draw_range (
1037
1024
buffer,
1038
1025
underline. multiline_horizontal ,
1039
1026
line_offset + pos,
1040
1027
width_offset + depth,
1041
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1028
+ code_offset + pre ,
1042
1029
underline. style ,
1043
1030
) ;
1044
1031
}
@@ -1061,11 +1048,18 @@ impl HumanEmitter {
1061
1048
let underline = self . underline ( annotation. is_primary ) ;
1062
1049
let pos = pos + 1 ;
1063
1050
1051
+ let code_offset = code_offset
1052
+ + source_string
1053
+ . chars ( )
1054
+ . take ( annotation. start_col . file )
1055
+ . skip ( left)
1056
+ . map ( |c| char_width ( c) )
1057
+ . sum :: < usize > ( ) ;
1064
1058
if pos > 1 && ( annotation. has_label ( ) || annotation. takes_space ( ) ) {
1065
1059
for p in line_offset + 1 ..=line_offset + pos {
1066
1060
buffer. putc (
1067
1061
p,
1068
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1062
+ code_offset,
1069
1063
match annotation. annotation_type {
1070
1064
AnnotationType :: MultilineLine ( _) => underline. multiline_vertical ,
1071
1065
_ => underline. vertical_text_line ,
@@ -1076,7 +1070,7 @@ impl HumanEmitter {
1076
1070
if let AnnotationType :: MultilineStart ( _) = annotation. annotation_type {
1077
1071
buffer. putc (
1078
1072
line_offset + pos,
1079
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1073
+ code_offset,
1080
1074
underline. bottom_right ,
1081
1075
underline. style ,
1082
1076
) ;
@@ -1086,7 +1080,7 @@ impl HumanEmitter {
1086
1080
{
1087
1081
buffer. putc (
1088
1082
line_offset + pos,
1089
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1083
+ code_offset,
1090
1084
underline. multiline_bottom_right_with_text ,
1091
1085
underline. style ,
1092
1086
) ;
@@ -1144,13 +1138,30 @@ impl HumanEmitter {
1144
1138
let style =
1145
1139
if annotation. is_primary { Style :: LabelPrimary } else { Style :: LabelSecondary } ;
1146
1140
let ( pos, col) = if pos == 0 {
1147
- if annotation. end_col . display == 0 {
1148
- ( pos + 1 , ( annotation. end_col . display + 2 ) . saturating_sub ( left) )
1141
+ let pre: usize = source_string
1142
+ . chars ( )
1143
+ . take ( annotation. end_col . file )
1144
+ . skip ( left)
1145
+ . map ( |c| char_width ( c) )
1146
+ . sum ( ) ;
1147
+ if annotation. end_col . file == 0 {
1148
+ ( pos + 1 , ( pre + 2 ) )
1149
1149
} else {
1150
- ( pos + 1 , ( annotation. end_col . display + 1 ) . saturating_sub ( left) )
1150
+ let pad = if annotation. end_col . file - annotation. start_col . file == 0 {
1151
+ 2
1152
+ } else {
1153
+ 1
1154
+ } ;
1155
+ ( pos + 1 , ( pre + pad) )
1151
1156
}
1152
1157
} else {
1153
- ( pos + 2 , annotation. start_col . display . saturating_sub ( left) )
1158
+ let pre: usize = source_string
1159
+ . chars ( )
1160
+ . take ( annotation. start_col . file )
1161
+ . skip ( left)
1162
+ . map ( |c| char_width ( c) )
1163
+ . sum ( ) ;
1164
+ ( pos + 2 , pre)
1154
1165
} ;
1155
1166
if let Some ( ref label) = annotation. label {
1156
1167
buffer. puts ( line_offset + pos, code_offset + col, label, style) ;
@@ -1183,14 +1194,35 @@ impl HumanEmitter {
1183
1194
// | _^ test
1184
1195
for & ( pos, annotation) in & annotations_position {
1185
1196
let uline = self . underline ( annotation. is_primary ) ;
1186
- for p in annotation. start_col . display ..annotation. end_col . display {
1197
+ let width = annotation. end_col . file - annotation. start_col . file ;
1198
+ let previous: String =
1199
+ source_string. chars ( ) . take ( annotation. start_col . file ) . skip ( left) . collect ( ) ;
1200
+ let underlined: String =
1201
+ source_string. chars ( ) . skip ( annotation. start_col . file ) . take ( width) . collect ( ) ;
1202
+ debug ! ( ?previous, ?underlined) ;
1203
+ let code_offset = code_offset
1204
+ + source_string
1205
+ . chars ( )
1206
+ . take ( annotation. start_col . file )
1207
+ . skip ( left)
1208
+ . map ( |c| char_width ( c) )
1209
+ . sum :: < usize > ( ) ;
1210
+ let ann_width: usize = source_string
1211
+ . chars ( )
1212
+ . skip ( annotation. start_col . file )
1213
+ . take ( width)
1214
+ . map ( |c| char_width ( c) )
1215
+ . sum ( ) ;
1216
+ let ann_width = if ann_width == 0
1217
+ && matches ! ( annotation. annotation_type, AnnotationType :: Singleline )
1218
+ {
1219
+ 1
1220
+ } else {
1221
+ ann_width
1222
+ } ;
1223
+ for p in 0 ..ann_width {
1187
1224
// The default span label underline.
1188
- buffer. putc (
1189
- line_offset + 1 ,
1190
- ( code_offset + p) . saturating_sub ( left) ,
1191
- uline. underline ,
1192
- uline. style ,
1193
- ) ;
1225
+ buffer. putc ( line_offset + 1 , code_offset + p, uline. underline , uline. style ) ;
1194
1226
}
1195
1227
1196
1228
if pos == 0
@@ -1202,7 +1234,7 @@ impl HumanEmitter {
1202
1234
// The beginning of a multiline span with its leftward moving line on the same line.
1203
1235
buffer. putc (
1204
1236
line_offset + 1 ,
1205
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1237
+ code_offset,
1206
1238
match annotation. annotation_type {
1207
1239
AnnotationType :: MultilineStart ( _) => uline. top_right_flat ,
1208
1240
AnnotationType :: MultilineEnd ( _) => uline. multiline_end_same_line ,
@@ -1220,7 +1252,7 @@ impl HumanEmitter {
1220
1252
// so we start going down first.
1221
1253
buffer. putc (
1222
1254
line_offset + 1 ,
1223
- ( code_offset + annotation . start_col . display ) . saturating_sub ( left ) ,
1255
+ code_offset,
1224
1256
match annotation. annotation_type {
1225
1257
AnnotationType :: MultilineStart ( _) => uline. multiline_start_down ,
1226
1258
AnnotationType :: MultilineEnd ( _) => uline. multiline_end_up ,
@@ -1230,12 +1262,7 @@ impl HumanEmitter {
1230
1262
) ;
1231
1263
} else if pos != 0 && annotation. has_label ( ) {
1232
1264
// The beginning of a span label with an actual label, we'll point down.
1233
- buffer. putc (
1234
- line_offset + 1 ,
1235
- ( code_offset + annotation. start_col . display ) . saturating_sub ( left) ,
1236
- uline. label_start ,
1237
- uline. style ,
1238
- ) ;
1265
+ buffer. putc ( line_offset + 1 , code_offset, uline. label_start , uline. style ) ;
1239
1266
}
1240
1267
}
1241
1268
@@ -1718,17 +1745,11 @@ impl HumanEmitter {
1718
1745
// non-rustc_lexer::is_whitespace() chars are reported as an
1719
1746
// error (ex. no-break-spaces \u{a0}), and thus can't be considered
1720
1747
// for removal during error reporting.
1748
+ // FIXME: doesn't account for '\t' properly.
1721
1749
let leading_whitespace = source_string
1722
1750
. chars ( )
1723
1751
. take_while ( |c| rustc_lexer:: is_whitespace ( * c) )
1724
- . map ( |c| {
1725
- match c {
1726
- // Tabs are displayed as 4 spaces
1727
- '\t' => 4 ,
1728
- _ => 1 ,
1729
- }
1730
- } )
1731
- . sum ( ) ;
1752
+ . count ( ) ;
1732
1753
if source_string. chars ( ) . any ( |c| !rustc_lexer:: is_whitespace ( c) ) {
1733
1754
whitespace_margin = min ( whitespace_margin, leading_whitespace) ;
1734
1755
}
@@ -1742,8 +1763,8 @@ impl HumanEmitter {
1742
1763
let mut span_left_margin = usize:: MAX ;
1743
1764
for line in & annotated_file. lines {
1744
1765
for ann in & line. annotations {
1745
- span_left_margin = min ( span_left_margin, ann. start_col . display ) ;
1746
- span_left_margin = min ( span_left_margin, ann. end_col . display ) ;
1766
+ span_left_margin = min ( span_left_margin, ann. start_col . file ) ;
1767
+ span_left_margin = min ( span_left_margin, ann. end_col . file ) ;
1747
1768
}
1748
1769
}
1749
1770
if span_left_margin == usize:: MAX {
@@ -1763,12 +1784,12 @@ impl HumanEmitter {
1763
1784
. map_or ( 0 , |s| s. len ( ) ) ,
1764
1785
) ;
1765
1786
for ann in & line. annotations {
1766
- span_right_margin = max ( span_right_margin, ann. start_col . display ) ;
1767
- span_right_margin = max ( span_right_margin, ann. end_col . display ) ;
1787
+ span_right_margin = max ( span_right_margin, ann. start_col . file ) ;
1788
+ span_right_margin = max ( span_right_margin, ann. end_col . file ) ;
1768
1789
// FIXME: account for labels not in the same line
1769
1790
let label_right = ann. label . as_ref ( ) . map_or ( 0 , |l| l. len ( ) + 1 ) ;
1770
1791
label_right_margin =
1771
- max ( label_right_margin, ann. end_col . display + label_right) ;
1792
+ max ( label_right_margin, ann. end_col . file + label_right) ;
1772
1793
}
1773
1794
}
1774
1795
0 commit comments