10
10
//
11
11
//===----------------------------------------------------------------------===//
12
12
13
+ import LSPLogging
14
+
13
15
public struct LineTable : Hashable {
14
16
@usableFromInline
15
17
var impl : [ String . Index ]
@@ -123,113 +125,242 @@ extension LineTable {
123
125
}
124
126
}
125
127
126
- extension LineTable {
128
+ // MARK: - Position translation
127
129
128
- // MARK: - Position translation
130
+ extension LineTable {
131
+ // MARK: line:column <-> String.Index
129
132
130
- /// Returns `String.Index` of given logical position.
133
+ /// Converts the given UTF-16-based `line:column`` position to a `String.Index`.
134
+ ///
135
+ /// If the position does not refer to a valid position with in the source file, returns `nil` and logs a fault
136
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
131
137
///
132
138
/// - parameter line: Line number (zero-based).
133
139
/// - parameter utf16Column: UTF-16 column offset (zero-based).
134
140
@inlinable
135
- public func stringIndexOf( line: Int , utf16Column: Int ) -> String . Index ? {
141
+ public func stringIndexOf(
142
+ line: Int ,
143
+ utf16Column: Int ,
144
+ callerFile: StaticString = #fileID,
145
+ callerLine: UInt = #line
146
+ ) -> String . Index ? {
136
147
guard line < count else {
137
- // Line out of range.
148
+ logger. fault (
149
+ """
150
+ Unable to get string index for \( line) : \( utf16Column) (UTF-16) because line is out of range \
151
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
152
+ """
153
+ )
138
154
return nil
139
155
}
140
156
let lineSlice = self [ line]
141
- return content. utf16. index ( lineSlice. startIndex, offsetBy: utf16Column, limitedBy: lineSlice. endIndex)
157
+ guard let index = content. utf16. index ( lineSlice. startIndex, offsetBy: utf16Column, limitedBy: lineSlice. endIndex)
158
+ else {
159
+ logger. fault (
160
+ """
161
+ Unable to get string index for \( line) : \( utf16Column) (UTF-16) because column is out of range \
162
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
163
+ """
164
+ )
165
+ return nil
166
+ }
167
+ return index
142
168
}
143
169
144
- /// Returns `String.Index` of given logical position.
170
+ /// Converts the given UTF-8-based `line:column`` position to a `String.Index`.
171
+ ///
172
+ /// If the position does not refer to a valid position with in the source file, returns `nil` and logs a fault
173
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
145
174
///
146
175
/// - parameter line: Line number (zero-based).
147
176
/// - parameter utf8Column: UTF-8 column offset (zero-based).
148
177
@inlinable
149
- public func stringIndexOf( line: Int , utf8Column: Int ) -> String . Index ? {
178
+ public func stringIndexOf(
179
+ line: Int ,
180
+ utf8Column: Int ,
181
+ callerFile: StaticString = #fileID,
182
+ callerLine: UInt = #line
183
+ ) -> String . Index ? {
150
184
guard 0 <= line, line < count else {
151
- // Line out of range.
185
+ logger. fault (
186
+ """
187
+ Unable to get string index for \( line) : \( utf8Column) (UTF-8) because line is out of range \
188
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
189
+ """
190
+ )
152
191
return nil
153
192
}
154
193
guard 0 <= utf8Column else {
155
- // Column out of range.
194
+ logger. fault (
195
+ """
196
+ Unable to get string index for \( line) : \( utf8Column) (UTF-8) because column is out of range \
197
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
198
+ """
199
+ )
156
200
return nil
157
201
}
158
202
let lineSlice = self [ line]
159
203
return content. utf8. index ( lineSlice. startIndex, offsetBy: utf8Column, limitedBy: lineSlice. endIndex)
160
204
}
161
205
162
- /// Returns UTF8 buffer offset of given logical position.
206
+ // MARK: line:column <-> UTF-8 offset
207
+
208
+ /// Converts the given UTF-16-based `line:column`` position to a UTF-8 offset within the source file.
209
+ ///
210
+ /// If the position does not refer to a valid position with in the source file, returns `nil` and logs a fault
211
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
163
212
///
164
213
/// - parameter line: Line number (zero-based).
165
214
/// - parameter utf16Column: UTF-16 column offset (zero-based).
166
215
@inlinable
167
- public func utf8OffsetOf( line: Int , utf16Column: Int ) -> Int ? {
168
- guard let stringIndex = stringIndexOf ( line: line, utf16Column: utf16Column) else {
216
+ public func utf8OffsetOf(
217
+ line: Int ,
218
+ utf16Column: Int ,
219
+ callerFile: StaticString = #fileID,
220
+ callerLine: UInt = #line
221
+ ) -> Int ? {
222
+ guard
223
+ let stringIndex = stringIndexOf (
224
+ line: line,
225
+ utf16Column: utf16Column,
226
+ callerFile: callerFile,
227
+ callerLine: callerLine
228
+ )
229
+ else {
169
230
return nil
170
231
}
171
232
return content. utf8. distance ( from: content. startIndex, to: stringIndex)
172
233
}
173
234
174
- /// Returns UTF8 buffer offset of given logical position.
235
+ /// Converts the given UTF-8-based `line:column`` position to a UTF-8 offset within the source file.
236
+ ///
237
+ /// If the position does not refer to a valid position with in the source file, returns `nil` and logs a fault
238
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
175
239
///
176
240
/// - parameter line: Line number (zero-based).
177
241
/// - parameter utf8Column: UTF-8 column offset (zero-based).
178
242
@inlinable
179
- public func utf8OffsetOf( line: Int , utf8Column: Int ) -> Int ? {
180
- guard let stringIndex = stringIndexOf ( line: line, utf8Column: utf8Column) else {
243
+ public func utf8OffsetOf(
244
+ line: Int ,
245
+ utf8Column: Int ,
246
+ callerFile: StaticString = #fileID,
247
+ callerLine: UInt = #line
248
+ ) -> Int ? {
249
+ guard
250
+ let stringIndex = stringIndexOf (
251
+ line: line,
252
+ utf8Column: utf8Column,
253
+ callerFile: callerFile,
254
+ callerLine: callerLine
255
+ )
256
+ else {
181
257
return nil
182
258
}
183
259
return content. utf8. distance ( from: content. startIndex, to: stringIndex)
184
260
}
185
261
186
- /// Returns logical position of given source offset.
262
+ /// Converts the given UTF-16-based line:column position to the UTF-8 offset of that position within the source file.
263
+ ///
264
+ /// If the position does not refer to a valid position with in the snapshot, returns `nil` and logs a fault
265
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
187
266
///
188
267
/// - parameter utf8Offset: UTF-8 buffer offset (zero-based).
189
268
@inlinable
190
- public func lineAndUTF16ColumnOf( utf8Offset: Int ) -> ( line: Int , utf16Column: Int ) ? {
269
+ public func lineAndUTF16ColumnOf(
270
+ utf8Offset: Int ,
271
+ callerFile: StaticString = #fileID,
272
+ callerLine: UInt = #line
273
+ ) -> ( line: Int , utf16Column: Int ) ? {
191
274
guard utf8Offset <= content. utf8. count else {
192
- // Offset ouf of range.
275
+ logger. fault (
276
+ """
277
+ Unable to get line and UTF-16 column for UTF-8 offset \( utf8Offset) because offset is out of range \
278
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
279
+ """
280
+ )
193
281
return nil
194
282
}
195
283
return lineAndUTF16ColumnOf ( content. utf8. index ( content. startIndex, offsetBy: utf8Offset) )
196
284
}
197
285
198
- @inlinable func lineAndUTF8ColumnOf( utf8Offset: Int ) -> ( line: Int , utf8Column: Int ) ? {
199
- guard let ( line, utf16Column) = lineAndUTF16ColumnOf ( utf8Offset: utf8Offset) else {
286
+ /// Converts the given UTF-8-based line:column position to the UTF-8 offset of that position within the source file.
287
+ ///
288
+ /// If the position does not refer to a valid position with in the snapshot, returns `nil` and logs a fault
289
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
290
+ @inlinable func lineAndUTF8ColumnOf(
291
+ utf8Offset: Int ,
292
+ callerFile: StaticString = #fileID,
293
+ callerLine: UInt = #line
294
+ ) -> ( line: Int , utf8Column: Int ) ? {
295
+ guard
296
+ let ( line, utf16Column) = lineAndUTF16ColumnOf (
297
+ utf8Offset: utf8Offset,
298
+ callerFile: callerFile,
299
+ callerLine: callerLine
300
+ )
301
+ else {
200
302
return nil
201
303
}
202
- guard let utf8Column = utf8ColumnAt ( line: line, utf16Column: utf16Column) else {
304
+ guard
305
+ let utf8Column = utf8ColumnAt (
306
+ line: line,
307
+ utf16Column: utf16Column,
308
+ callerFile: callerFile,
309
+ callerLine: callerLine
310
+ )
311
+ else {
203
312
return nil
204
313
}
205
314
return ( line, utf8Column)
206
315
}
207
316
208
- /// Returns UTF16 column offset at UTF8 version of logical position.
317
+ // MARK: UTF-8 line:column <-> UTF-16 line:column
318
+
319
+ /// Returns UTF-16 column offset at UTF-8 based `line:column` position.
320
+ ///
321
+ /// If the position does not refer to a valid position with in the snapshot, returns `nil` and logs a fault
322
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
209
323
///
210
324
/// - parameter line: Line number (zero-based).
211
325
/// - parameter utf8Column: UTF-8 column offset (zero-based).
212
326
@inlinable
213
- public func utf16ColumnAt( line: Int , utf8Column: Int ) -> Int ? {
327
+ public func utf16ColumnAt(
328
+ line: Int ,
329
+ utf8Column: Int ,
330
+ callerFile: StaticString = #fileID,
331
+ callerLine: UInt = #line
332
+ ) -> Int ? {
214
333
return convertColumn (
215
334
line: line,
216
335
column: utf8Column,
217
336
indexFunction: content. utf8. index ( _: offsetBy: limitedBy: ) ,
218
- distanceFunction: content. utf16. distance ( from: to: )
337
+ distanceFunction: content. utf16. distance ( from: to: ) ,
338
+ callerFile: callerFile,
339
+ callerLine: callerLine
219
340
)
220
341
}
221
342
222
- /// Returns UTF8 column offset at UTF16 version of logical position.
343
+ /// Returns UTF-8 column offset at UTF-16 based `line:column` position.
344
+ ///
345
+ /// If the position does not refer to a valid position with in the snapshot, returns `nil` and logs a fault
346
+ /// containing the file and line of the caller (from `callerFile` and `callerLine`).
223
347
///
224
348
/// - parameter line: Line number (zero-based).
225
349
/// - parameter utf16Column: UTF-16 column offset (zero-based).
226
350
@inlinable
227
- public func utf8ColumnAt( line: Int , utf16Column: Int ) -> Int ? {
351
+ public func utf8ColumnAt(
352
+ line: Int ,
353
+ utf16Column: Int ,
354
+ callerFile: StaticString = #fileID,
355
+ callerLine: UInt = #line
356
+ ) -> Int ? {
228
357
return convertColumn (
229
358
line: line,
230
359
column: utf16Column,
231
360
indexFunction: content. utf16. index ( _: offsetBy: limitedBy: ) ,
232
- distanceFunction: content. utf8. distance ( from: to: )
361
+ distanceFunction: content. utf8. distance ( from: to: ) ,
362
+ callerFile: callerFile,
363
+ callerLine: callerLine
233
364
)
234
365
}
235
366
@@ -238,15 +369,27 @@ extension LineTable {
238
369
line: Int ,
239
370
column: Int ,
240
371
indexFunction: ( Substring . Index , Int , Substring . Index ) -> Substring . Index ? ,
241
- distanceFunction: ( Substring . Index , Substring . Index ) -> Int
372
+ distanceFunction: ( Substring . Index , Substring . Index ) -> Int ,
373
+ callerFile: StaticString = #fileID,
374
+ callerLine: UInt = #line
242
375
) -> Int ? {
243
376
guard line < count else {
244
- // Line out of range.
377
+ logger. fault (
378
+ """
379
+ Unable to convert column of \( line) : \( column) because line is out of range \
380
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
381
+ """
382
+ )
245
383
return nil
246
384
}
247
385
let lineSlice = self [ line]
248
386
guard let targetIndex = indexFunction ( lineSlice. startIndex, column, lineSlice. endIndex) else {
249
- // Column out of range
387
+ logger. fault (
388
+ """
389
+ Unable to convert column of \( line) : \( column) because column is out of range \
390
+ ( \( callerFile, privacy: . public) : \( callerLine, privacy: . public) )
391
+ """
392
+ )
250
393
return nil
251
394
}
252
395
return distanceFunction ( lineSlice. startIndex, targetIndex)
0 commit comments