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