func completionsFromSKDResponse()

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
  }