return Defaults;
}
+CompletionItemKindBitset defaultCompletionItemKinds() {
+ CompletionItemKindBitset Defaults;
+ for (size_t I = CompletionItemKindMin;
+ I <= static_cast<size_t>(CompletionItemKind::Reference); ++I)
+ Defaults.set(I);
+ return Defaults;
+}
+
} // namespace
void ClangdLSPServer::onInitialize(InitializeParams &Params) {
Params.capabilities.textDocument.publishDiagnostics.categorySupport;
if (Params.capabilities.workspace && Params.capabilities.workspace->symbol &&
- Params.capabilities.workspace->symbol->symbolKind) {
+ Params.capabilities.workspace->symbol->symbolKind &&
+ Params.capabilities.workspace->symbol->symbolKind->valueSet) {
for (SymbolKind Kind :
*Params.capabilities.workspace->symbol->symbolKind->valueSet) {
SupportedSymbolKinds.set(static_cast<size_t>(Kind));
}
}
+ if (Params.capabilities.textDocument.completion.completionItemKind &&
+ Params.capabilities.textDocument.completion.completionItemKind->valueSet)
+ for (CompletionItemKind Kind : *Params.capabilities.textDocument.completion
+ .completionItemKind->valueSet)
+ SupportedCompletionItemKinds.set(static_cast<size_t>(Kind));
+
reply(json::Object{
{{"capabilities",
json::Object{
return replyError(List.takeError());
CompletionList LSPList;
LSPList.isIncomplete = List->HasMore;
- for (const auto &R : List->Completions)
- LSPList.items.push_back(R.render(CCOpts));
+ for (const auto &R : List->Completions) {
+ CompletionItem C = R.render(CCOpts);
+ C.kind = adjustKindToCapability(
+ C.kind, SupportedCompletionItemKinds);
+ LSPList.items.push_back(std::move(C));
+ }
return reply(std::move(LSPList));
});
}
: CompilationDB::makeDirectoryBased(
std::move(CompileCommandsDir))),
CCOpts(CCOpts), SupportedSymbolKinds(defaultSymbolKinds()),
+ SupportedCompletionItemKinds(defaultCompletionItemKinds()),
Server(new ClangdServer(CDB.getCDB(), FSProvider, /*DiagConsumer=*/*this,
Opts)) {}
ClangdDiagnosticOptions DiagOpts;
/// The supported kinds of the client.
SymbolKindBitset SupportedSymbolKinds;
+ /// The supported completion item kinds of the client.
+ CompletionItemKindBitset SupportedCompletionItemKinds;
// Store of the current versions of the open documents.
DraftStore DraftMgr;
return std::move(Result);
}
+bool fromJSON(const json::Value &E, CompletionItemKind &Out) {
+ if (auto T = E.getAsInteger()) {
+ if (*T < static_cast<int>(CompletionItemKind::Text) ||
+ *T > static_cast<int>(CompletionItemKind::TypeParameter))
+ return false;
+ Out = static_cast<CompletionItemKind>(*T);
+ return true;
+ }
+ return false;
+}
+
+CompletionItemKind
+adjustKindToCapability(CompletionItemKind Kind,
+ CompletionItemKindBitset &supportedCompletionItemKinds) {
+ auto KindVal = static_cast<size_t>(Kind);
+ if (KindVal >= CompletionItemKindMin &&
+ KindVal <= supportedCompletionItemKinds.size() &&
+ supportedCompletionItemKinds[KindVal])
+ return Kind;
+
+ switch (Kind) {
+ // Provide some fall backs for common kinds that are close enough.
+ case CompletionItemKind::Folder:
+ return CompletionItemKind::File;
+ case CompletionItemKind::EnumMember:
+ return CompletionItemKind::Enum;
+ case CompletionItemKind::Struct:
+ return CompletionItemKind::Class;
+ default:
+ return CompletionItemKind::Text;
+ }
+}
+
+bool fromJSON(const json::Value &E, std::vector<CompletionItemKind> &Out) {
+ if (auto *A = E.getAsArray()) {
+ Out.clear();
+ for (size_t I = 0; I < A->size(); ++I) {
+ CompletionItemKind KindOut;
+ if (fromJSON((*A)[I], KindOut))
+ Out.push_back(KindOut);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool fromJSON(const json::Value &Params, CompletionItemKindCapabilities &R) {
+ json::ObjectMapper O(Params);
+ return O && O.map("valueSet", R.valueSet);
+}
+
json::Value toJSON(const CompletionItem &CI) {
assert(!CI.label.empty() && "completion item label is required");
json::Object Result{{"label", CI.label}};
};
bool fromJSON(const llvm::json::Value &, CompletionItemClientCapabilities &);
+/// The kind of a completion entry.
+enum class CompletionItemKind {
+ Missing = 0,
+ Text = 1,
+ Method = 2,
+ Function = 3,
+ Constructor = 4,
+ Field = 5,
+ Variable = 6,
+ Class = 7,
+ Interface = 8,
+ Module = 9,
+ Property = 10,
+ Unit = 11,
+ Value = 12,
+ Enum = 13,
+ Keyword = 14,
+ Snippet = 15,
+ Color = 16,
+ File = 17,
+ Reference = 18,
+ Folder = 19,
+ EnumMember = 20,
+ Constant = 21,
+ Struct = 22,
+ Event = 23,
+ Operator = 24,
+ TypeParameter = 25,
+};
+bool fromJSON(const llvm::json::Value &, CompletionItemKind &);
+
+struct CompletionItemKindCapabilities {
+ /// The CompletionItemKinds that the client supports. If not set, the client
+ /// only supports <= CompletionItemKind::Reference and will not fall back to a
+ /// valid default value.
+ llvm::Optional<std::vector<CompletionItemKind>> valueSet;
+};
+// Discards unknown CompletionItemKinds.
+bool fromJSON(const llvm::json::Value &, std::vector<CompletionItemKind> &);
+bool fromJSON(const llvm::json::Value &, CompletionItemKindCapabilities &);
+
+constexpr auto CompletionItemKindMin =
+ static_cast<size_t>(CompletionItemKind::Text);
+constexpr auto CompletionItemKindMax =
+ static_cast<size_t>(CompletionItemKind::TypeParameter);
+using CompletionItemKindBitset = std::bitset<CompletionItemKindMax + 1>;
+CompletionItemKind
+adjustKindToCapability(CompletionItemKind Kind,
+ CompletionItemKindBitset &supportedCompletionItemKinds);
+
struct CompletionClientCapabilities {
/// Whether completion supports dynamic registration.
bool dynamicRegistration = false;
/// The client supports the following `CompletionItem` specific capabilities.
CompletionItemClientCapabilities completionItem;
- // NOTE: not used by clangd at the moment.
- // llvm::Optional<CompletionItemKindCapabilities> completionItemKind;
+ /// The CompletionItemKinds that the client supports. If not set, the client
+ /// only supports <= CompletionItemKind::Reference and will not fall back to a
+ /// valid default value.
+ llvm::Optional<CompletionItemKindCapabilities> completionItemKind;
/// The client supports to send additional context information for a
/// `textDocument/completion` request.
/// value.
llvm::Optional<std::vector<SymbolKind>> valueSet;
};
+// Discards unknown SymbolKinds.
bool fromJSON(const llvm::json::Value &, std::vector<SymbolKind> &);
bool fromJSON(const llvm::json::Value &, SymbolKindCapabilities &);
SymbolKind adjustKindToCapability(SymbolKind Kind,
};
llvm::json::Value toJSON(const Hover &H);
-/// The kind of a completion entry.
-enum class CompletionItemKind {
- Missing = 0,
- Text = 1,
- Method = 2,
- Function = 3,
- Constructor = 4,
- Field = 5,
- Variable = 6,
- Class = 7,
- Interface = 8,
- Module = 9,
- Property = 10,
- Unit = 11,
- Value = 12,
- Enum = 13,
- Keyword = 14,
- Snippet = 15,
- Color = 16,
- File = 17,
- Reference = 18,
- Folder = 19,
- EnumMember = 20,
- Constant = 21,
- Struct = 22,
- Event = 23,
- Operator = 24,
- TypeParameter = 25,
-};
-
/// Defines whether the insert text in a completion item should be interpreted
/// as plain text or a snippet.
enum class InsertTextFormat {