diff --git a/Sources/SourceKitLSP/Swift/CodeCompletionSession.swift b/Sources/SourceKitLSP/Swift/CodeCompletionSession.swift index 97f22b645..91c28152a 100644 --- a/Sources/SourceKitLSP/Swift/CodeCompletionSession.swift +++ b/Sources/SourceKitLSP/Swift/CodeCompletionSession.swift @@ -280,19 +280,11 @@ class CodeCompletionSession { // MARK: - Helpers - private func expandClosurePlaceholders( - insertText: String, - utf8CodeUnitsToErase: Int, - requestPosition: Position - ) -> String? { + private func expandClosurePlaceholders(insertText: String) -> String? { guard insertText.contains("<#") && insertText.contains("->") else { // Fast path: There is no closure placeholder to expand return nil } - guard requestPosition.line < snapshot.lineTable.count else { - logger.error("Request position is past the last line") - return nil - } let strippedPrefix: String let exprToExpand: String @@ -336,79 +328,63 @@ class CodeCompletionSession { requestPosition: Position, isIncomplete: Bool ) -> CompletionList { - var result = CompletionList(isIncomplete: isIncomplete, items: []) - - completions.forEach { (i: Int, value: SKDResponseDictionary) -> Bool in - guard let name: String = value[keys.description] else { - return true // continue + let completionItems = completions.compactMap { (value: SKDResponseDictionary) -> CompletionItem? in + guard let name: String = value[keys.description], + var insertText: String = value[keys.sourceText] + else { + return nil } var filterName: String? = value[keys.name] - var insertText: String? = value[keys.sourceText] let typeName: String? = value[sourcekitd.keys.typeName] let docBrief: String? = value[sourcekitd.keys.docBrief] let utf8CodeUnitsToErase: Int = value[sourcekitd.keys.numBytesToErase] ?? 0 - if let insertTextUnwrapped = insertText { - insertText = - expandClosurePlaceholders( - insertText: insertTextUnwrapped, - utf8CodeUnitsToErase: utf8CodeUnitsToErase, - requestPosition: requestPosition - ) ?? insertText + if let closureExpanded = expandClosurePlaceholders(insertText: insertText) { + insertText = closureExpanded } - let text = insertText.map { - rewriteSourceKitPlaceholders(in: $0, clientSupportsSnippets: clientSupportsSnippets) - } + let text = rewriteSourceKitPlaceholders(in: insertText, clientSupportsSnippets: clientSupportsSnippets) let isInsertTextSnippet = clientSupportsSnippets && text != insertText let textEdit: TextEdit? - if let text = text { - let edit = self.computeCompletionTextEdit( - completionPos: completionPos, - requestPosition: requestPosition, - utf8CodeUnitsToErase: utf8CodeUnitsToErase, - newText: text, - snapshot: snapshot - ) - textEdit = edit - - 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 filterPrefix = snapshot.text[snapshot.indexRange(of: textEdit.range.lowerBound..