@@ -68,6 +68,22 @@ public struct DiagnosticsFormatter {
68
68
var isFreeOfAnnotations : Bool {
69
69
return diagnostics. isEmpty && suffixText. isEmpty
70
70
}
71
+
72
+ /// Converts a UTF-8 column index into an index that considers each character as a single column, not each UTF-8
73
+ /// byte.
74
+ ///
75
+ /// For example the 👨👩👧👦 character is considered as a single character, not 25 bytes.
76
+ ///
77
+ /// Both the input and the output column are 1-based.
78
+ func characterColumn( ofUtf8Column utf8Column: Int ) -> Int {
79
+ let index =
80
+ sourceString. utf8. index (
81
+ sourceString. utf8. startIndex,
82
+ offsetBy: utf8Column - 1 ,
83
+ limitedBy: sourceString. utf8. endIndex
84
+ ) ?? sourceString. utf8. endIndex
85
+ return sourceString. distance ( from: sourceString. startIndex, to: index) + 1
86
+ }
71
87
}
72
88
73
89
/// Number of lines which should be printed before and after the diagnostic message
@@ -139,7 +155,7 @@ public struct DiagnosticsFormatter {
139
155
140
156
let endColumn : Int
141
157
if endLine > lineNumber {
142
- endColumn = annotatedLine. sourceString. count
158
+ endColumn = annotatedLine. sourceString. utf8 . count
143
159
} else if endLine == lineNumber {
144
160
endColumn = endLoc. column
145
161
} else {
@@ -274,9 +290,13 @@ public struct DiagnosticsFormatter {
274
290
annotatedSource. append ( " \n " )
275
291
}
276
292
277
- let columnsWithDiagnostics = Set ( annotatedLine. diagnostics. map { $0. location ( converter: slc) . column } )
293
+ let columnsWithDiagnostics = Set (
294
+ annotatedLine. diagnostics. map {
295
+ annotatedLine. characterColumn ( ofUtf8Column: $0. location ( converter: slc) . column)
296
+ }
297
+ )
278
298
let diagsPerColumn = Dictionary ( grouping: annotatedLine. diagnostics) { diag in
279
- diag. location ( converter: slc) . column
299
+ annotatedLine . characterColumn ( ofUtf8Column : diag. location ( converter: slc) . column)
280
300
} . sorted { lhs, rhs in
281
301
lhs. key > rhs. key
282
302
}
0 commit comments