@@ -280,19 +280,11 @@ class CodeCompletionSession {
280
280
281
281
// MARK: - Helpers
282
282
283
- private func expandClosurePlaceholders(
284
- insertText: String ,
285
- utf8CodeUnitsToErase: Int ,
286
- requestPosition: Position
287
- ) -> String ? {
283
+ private func expandClosurePlaceholders( insertText: String ) -> String ? {
288
284
guard insertText. contains ( " <# " ) && insertText. contains ( " -> " ) else {
289
285
// Fast path: There is no closure placeholder to expand
290
286
return nil
291
287
}
292
- guard requestPosition. line < snapshot. lineTable. count else {
293
- logger. error ( " Request position is past the last line " )
294
- return nil
295
- }
296
288
297
289
let strippedPrefix : String
298
290
let exprToExpand : String
@@ -336,79 +328,63 @@ class CodeCompletionSession {
336
328
requestPosition: Position ,
337
329
isIncomplete: Bool
338
330
) -> CompletionList {
339
- var result = CompletionList ( isIncomplete : isIncomplete , items : [ ] )
340
-
341
- completions . forEach { ( i : Int , value : SKDResponseDictionary ) -> Bool in
342
- guard let name : String = value [ keys . description ] else {
343
- return true // continue
331
+ let completionItems = completions . compactMap { ( value : SKDResponseDictionary ) -> CompletionItem ? in
332
+ guard let name : String = value [ keys . description ] ,
333
+ var insertText : String = value [ keys . sourceText ]
334
+ else {
335
+ return nil
344
336
}
345
337
346
338
var filterName : String ? = value [ keys. name]
347
- var insertText : String ? = value [ keys. sourceText]
348
339
let typeName : String ? = value [ sourcekitd. keys. typeName]
349
340
let docBrief : String ? = value [ sourcekitd. keys. docBrief]
350
341
let utf8CodeUnitsToErase : Int = value [ sourcekitd. keys. numBytesToErase] ?? 0
351
342
352
- if let insertTextUnwrapped = insertText {
353
- insertText =
354
- expandClosurePlaceholders (
355
- insertText: insertTextUnwrapped,
356
- utf8CodeUnitsToErase: utf8CodeUnitsToErase,
357
- requestPosition: requestPosition
358
- ) ?? insertText
343
+ if let closureExpanded = expandClosurePlaceholders ( insertText: insertText) {
344
+ insertText = closureExpanded
359
345
}
360
346
361
- let text = insertText. map {
362
- rewriteSourceKitPlaceholders ( in: $0, clientSupportsSnippets: clientSupportsSnippets)
363
- }
347
+ let text = rewriteSourceKitPlaceholders ( in: insertText, clientSupportsSnippets: clientSupportsSnippets)
364
348
let isInsertTextSnippet = clientSupportsSnippets && text != insertText
365
349
366
350
let textEdit : TextEdit ?
367
- if let text = text {
368
- let edit = self . computeCompletionTextEdit (
369
- completionPos: completionPos,
370
- requestPosition: requestPosition,
371
- utf8CodeUnitsToErase: utf8CodeUnitsToErase,
372
- newText: text,
373
- snapshot: snapshot
374
- )
375
- textEdit = edit
376
-
377
- if utf8CodeUnitsToErase != 0 , filterName != nil , let textEdit = textEdit {
378
- // To support the case where the client is doing prefix matching on the TextEdit range,
379
- // we need to prepend the deleted text to filterText.
380
- // This also works around a behaviour in VS Code that causes completions to not show up
381
- // if a '.' is being replaced for Optional completion.
382
- let filterPrefix = snapshot. text [ snapshot. indexRange ( of: textEdit. range. lowerBound..< completionPos) ]
383
- filterName = filterPrefix + filterName!
384
- }
385
- } else {
386
- textEdit = nil
351
+ let edit = self . computeCompletionTextEdit (
352
+ completionPos: completionPos,
353
+ requestPosition: requestPosition,
354
+ utf8CodeUnitsToErase: utf8CodeUnitsToErase,
355
+ newText: text,
356
+ snapshot: snapshot
357
+ )
358
+ textEdit = edit
359
+
360
+ if utf8CodeUnitsToErase != 0 , filterName != nil , let textEdit = textEdit {
361
+ // To support the case where the client is doing prefix matching on the TextEdit range,
362
+ // we need to prepend the deleted text to filterText.
363
+ // This also works around a behaviour in VS Code that causes completions to not show up
364
+ // if a '.' is being replaced for Optional completion.
365
+ let filterPrefix = snapshot. text [ snapshot. indexRange ( of: textEdit. range. lowerBound..< completionPos) ]
366
+ filterName = filterPrefix + filterName!
387
367
}
388
368
389
369
// Map SourceKit's not_recommended field to LSP's deprecated
390
- let notRecommended = ( value [ sourcekitd. keys. notRecommended] as Int ? ) . map ( { $0 != 0 } )
370
+ let notRecommended = ( value [ sourcekitd. keys. notRecommended] ?? 0 ) != 0
391
371
392
372
let kind : sourcekitd_api_uid_t ? = value [ sourcekitd. keys. kind]
393
- result. items. append (
394
- CompletionItem (
395
- label: name,
396
- kind: kind? . asCompletionItemKind ( sourcekitd. values) ?? . value,
397
- detail: typeName,
398
- documentation: docBrief != nil ? . markupContent( MarkupContent ( kind: . markdown, value: docBrief!) ) : nil ,
399
- deprecated: notRecommended ?? false ,
400
- sortText: nil ,
401
- filterText: filterName,
402
- insertText: text,
403
- insertTextFormat: isInsertTextSnippet ? . snippet : . plain,
404
- textEdit: textEdit. map ( CompletionItemEdit . textEdit)
405
- )
373
+ return CompletionItem (
374
+ label: name,
375
+ kind: kind? . asCompletionItemKind ( sourcekitd. values) ?? . value,
376
+ detail: typeName,
377
+ documentation: docBrief != nil ? . markupContent( MarkupContent ( kind: . markdown, value: docBrief!) ) : nil ,
378
+ deprecated: notRecommended,
379
+ sortText: nil ,
380
+ filterText: filterName,
381
+ insertText: text,
382
+ insertTextFormat: isInsertTextSnippet ? . snippet : . plain,
383
+ textEdit: textEdit. map ( CompletionItemEdit . textEdit)
406
384
)
407
-
408
- return true
409
385
}
410
386
411
- return result
387
+ return CompletionList ( isIncomplete : isIncomplete , items : completionItems )
412
388
}
413
389
414
390
private func computeCompletionTextEdit(
0 commit comments