[clangd] Add code completion support
Summary: Adds code completion support to clangd.
Reviewers: bkramer, malaperle-ericsson
Reviewed By: bkramer, malaperle-ericsson
Subscribers: stanionascu, malaperle-ericsson, cfe-commits
Differential Revision: https://reviews.llvm.org/D31328
llvm-svn: 299421
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 2814a54..163d982 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -570,3 +570,75 @@
}
return Result;
}
+
+llvm::Optional<TextDocumentPositionParams>
+TextDocumentPositionParams::parse(llvm::yaml::MappingNode *Params) {
+ TextDocumentPositionParams Result;
+ for (auto &NextKeyValue : *Params) {
+ auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
+ if (!KeyString)
+ return llvm::None;
+
+ llvm::SmallString<10> KeyStorage;
+ StringRef KeyValue = KeyString->getValue(KeyStorage);
+ auto *Value =
+ dyn_cast_or_null<llvm::yaml::MappingNode>(NextKeyValue.getValue());
+ if (!Value)
+ return llvm::None;
+
+ llvm::SmallString<10> Storage;
+ if (KeyValue == "textDocument") {
+ auto Parsed = TextDocumentIdentifier::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.textDocument = std::move(*Parsed);
+ } else if (KeyValue == "position") {
+ auto Parsed = Position::parse(Value);
+ if (!Parsed)
+ return llvm::None;
+ Result.position = std::move(*Parsed);
+ } else {
+ return llvm::None;
+ }
+ }
+ return Result;
+}
+
+std::string CompletionItem::unparse(const CompletionItem &CI) {
+ std::string Result = "{";
+ llvm::raw_string_ostream Os(Result);
+ assert(!CI.label.empty() && "completion item label is required");
+ Os << R"("label":")" << llvm::yaml::escape(CI.label) << R"(",)";
+ if (CI.kind != CompletionItemKind::Missing)
+ Os << R"("kind":)" << static_cast<int>(CI.kind) << R"(",)";
+ if (!CI.detail.empty())
+ Os << R"("detail":")" << llvm::yaml::escape(CI.detail) << R"(",)";
+ if (!CI.documentation.empty())
+ Os << R"("documentation":")" << llvm::yaml::escape(CI.documentation)
+ << R"(",)";
+ if (!CI.sortText.empty())
+ Os << R"("sortText":")" << llvm::yaml::escape(CI.sortText) << R"(",)";
+ if (!CI.filterText.empty())
+ Os << R"("filterText":")" << llvm::yaml::escape(CI.filterText) << R"(",)";
+ if (!CI.insertText.empty())
+ Os << R"("insertText":")" << llvm::yaml::escape(CI.insertText) << R"(",)";
+ if (CI.insertTextFormat != InsertTextFormat::Missing) {
+ Os << R"("insertTextFormat":")" << static_cast<int>(CI.insertTextFormat)
+ << R"(",)";
+ }
+ if (CI.textEdit)
+ Os << R"("textEdit":)" << TextEdit::unparse(*CI.textEdit) << ',';
+ if (!CI.additionalTextEdits.empty()) {
+ Os << R"("additionalTextEdits":[)";
+ for (const auto &Edit : CI.additionalTextEdits)
+ Os << TextEdit::unparse(Edit) << ",";
+ Os.flush();
+ // The list additionalTextEdits is guaranteed nonempty at this point.
+ // Replace the trailing comma with right brace.
+ Result.back() = ']';
+ }
+ Os.flush();
+ // Label is required, so Result is guaranteed to have a trailing comma.
+ Result.back() = '}';
+ return Result;
+}