in Sources/SourceKitLSP/Swift/CodeCompletion.swift [123:190]
func completionsFromSKDResponse(
_ completions: SKDResponseArray,
in snapshot: DocumentSnapshot,
completionPos: Position,
requestPosition: Position,
isIncomplete: Bool
) -> CompletionList {
var result = CompletionList(isIncomplete: isIncomplete, items: [])
completions.forEach { (i, value) -> Bool in
guard let name: String = value[self.keys.description] else {
return true // continue
}
var filterName: String? = value[self.keys.name]
let insertText: String? = value[self.keys.sourcetext]
let typeName: String? = value[self.keys.typename]
let docBrief: String? = value[self.keys.doc_brief]
let clientCompletionCapabilities = self.clientCapabilities.textDocument?.completion
let clientSupportsSnippets = clientCompletionCapabilities?.completionItem?.snippetSupport == true
let text = insertText.map {
self.rewriteSourceKitPlaceholders(inString: $0, clientSupportsSnippets: clientSupportsSnippets)
}
let isInsertTextSnippet = clientSupportsSnippets && text != insertText
let textEdit: TextEdit?
if let text = text {
let utf8CodeUnitsToErase: Int = value[self.keys.num_bytes_to_erase] ?? 0
textEdit = self.computeCompletionTextEdit(completionPos: completionPos, requestPosition: requestPosition, utf8CodeUnitsToErase: utf8CodeUnitsToErase, newText: text, snapshot: snapshot)
if utf8CodeUnitsToErase != 0, filterName != nil, let textEdit = textEdit {
// To support the case where the client is doing prefix matching on the TextEdit range,
// we need to prepend the deleted text to filterText.
// This also works around a behaviour in VS Code that causes completions to not show up
// if a '.' is being replaced for Optional completion.
let startIndex = snapshot.lineTable.stringIndexOf(line: textEdit.range.lowerBound.line, utf16Column: textEdit.range.lowerBound.utf16index)!
let endIndex = snapshot.lineTable.stringIndexOf(line: completionPos.line, utf16Column: completionPos.utf16index)!
let filterPrefix = snapshot.text[startIndex..<endIndex]
filterName = filterPrefix + filterName!
}
} else {
textEdit = nil
}
// Map SourceKit's not_recommended field to LSP's deprecated
let notRecommended = (value[self.keys.not_recommended] as Int?).map({ $0 != 0 })
let kind: sourcekitd_uid_t? = value[self.keys.kind]
result.items.append(CompletionItem(
label: name,
kind: kind?.asCompletionItemKind(self.values) ?? .value,
detail: typeName,
documentation: docBrief != nil ? .markupContent(MarkupContent(kind: .markdown, value: docBrief!)) : nil,
sortText: nil,
filterText: filterName,
textEdit: textEdit,
insertText: text,
insertTextFormat: isInsertTextSnippet ? .snippet : .plain,
deprecated: notRecommended ?? false
))
return true
}
return result
}