[clangd] Enable snippet completion based on client capabilities.

Summary: And remove -enable-snippets flag.

Reviewers: hokein, ioeric, sammccall

Reviewed By: ioeric

Subscribers: klimek, jkorous-apple, cfe-commits

Differential Revision: https://reviews.llvm.org/D43229

llvm-svn: 325242
This commit is contained in:
Ilya Biryukov 2018-02-15 14:32:57 +00:00
parent 6353ecb08a
commit 23bc73b626
5 changed files with 133 additions and 14 deletions

View File

@ -87,6 +87,14 @@ std::vector<TextEdit> replacementsToEdits(StringRef Code,
} // namespace
void ClangdLSPServer::onInitialize(InitializeParams &Params) {
if (Params.rootUri && !Params.rootUri->file.empty())
Server.setRootPath(Params.rootUri->file);
else if (Params.rootPath && !Params.rootPath->empty())
Server.setRootPath(*Params.rootPath);
CCOpts.EnableSnippets =
Params.capabilities.textDocument.completion.completionItem.snippetSupport;
reply(json::obj{
{{"capabilities",
json::obj{
@ -116,10 +124,6 @@ void ClangdLSPServer::onInitialize(InitializeParams &Params) {
{"commands", {ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND}},
}},
}}}});
if (Params.rootUri && !Params.rootUri->file.empty())
Server.setRootPath(Params.rootUri->file);
else if (Params.rootPath && !Params.rootPath->empty())
Server.setRootPath(*Params.rootPath);
}
void ClangdLSPServer::onShutdown(ShutdownParams &Params) {

View File

@ -150,6 +150,41 @@ bool fromJSON(const json::Expr &E, TraceLevel &Out) {
return false;
}
bool fromJSON(const json::Expr &Params, CompletionItemClientCapabilities &R) {
json::ObjectMapper O(Params);
if (!O)
return false;
O.map("snippetSupport", R.snippetSupport);
O.map("commitCharacterSupport", R.commitCharacterSupport);
return true;
}
bool fromJSON(const json::Expr &Params, CompletionClientCapabilities &R) {
json::ObjectMapper O(Params);
if (!O)
return false;
O.map("dynamicRegistration", R.dynamicRegistration);
O.map("completionItem", R.completionItem);
O.map("contextSupport", R.contextSupport);
return true;
}
bool fromJSON(const json::Expr &Params, TextDocumentClientCapabilities &R) {
json::ObjectMapper O(Params);
if (!O)
return false;
O.map("completion", R.completion);
return true;
}
bool fromJSON(const json::Expr &Params, ClientCapabilities &R) {
json::ObjectMapper O(Params);
if (!O)
return false;
O.map("textDocument", R.textDocument);
return true;
}
bool fromJSON(const json::Expr &Params, InitializeParams &R) {
json::ObjectMapper O(Params);
if (!O)
@ -159,6 +194,7 @@ bool fromJSON(const json::Expr &Params, InitializeParams &R) {
O.map("processId", R.processId);
O.map("rootUri", R.rootUri);
O.map("rootPath", R.rootPath);
O.map("capabilities", R.capabilities);
O.map("trace", R.trace);
// initializationOptions, capabilities unused
return true;

View File

@ -179,6 +179,51 @@ inline bool fromJSON(const json::Expr &, NoParams &) { return true; }
using ShutdownParams = NoParams;
using ExitParams = NoParams;
struct CompletionItemClientCapabilities {
/// Client supports snippets as insert text.
bool snippetSupport = false;
/// Client supports commit characters on a completion item.
bool commitCharacterSupport = false;
// Client supports the follow content formats for the documentation property.
// The order describes the preferred format of the client.
// NOTE: not used by clangd at the moment.
// std::vector<MarkupKind> documentationFormat;
};
bool fromJSON(const json::Expr &, CompletionItemClientCapabilities &);
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 client supports to send additional context information for a
/// `textDocument/completion` request.
bool contextSupport = false;
};
bool fromJSON(const json::Expr &, CompletionClientCapabilities &);
// FIXME: most of the capabilities are missing from this struct. Only the ones
// used by clangd are currently there.
struct TextDocumentClientCapabilities {
/// Capabilities specific to the `textDocument/completion`
CompletionClientCapabilities completion;
};
bool fromJSON(const json::Expr &, TextDocumentClientCapabilities &);
struct ClientCapabilities {
// Workspace specific client capabilities.
// NOTE: not used by clangd at the moment.
// WorkspaceClientCapabilities workspace;
// Text document specific client capabilities.
TextDocumentClientCapabilities textDocument;
};
bool fromJSON(const json::Expr &, ClientCapabilities &);
struct InitializeParams {
/// The process Id of the parent process that started
/// the server. Is null if the process has not been started by another
@ -201,8 +246,7 @@ struct InitializeParams {
// initializationOptions?: any;
/// The capabilities provided by the client (editor or tool)
/// Note: Not currently used by clangd
// ClientCapabilities capabilities;
ClientCapabilities capabilities;
/// The initial trace setting. If omitted trace is disabled ('off').
llvm::Optional<TraceLevel> trace;

View File

@ -58,13 +58,6 @@ static llvm::cl::opt<unsigned>
llvm::cl::desc("Number of async workers used by clangd"),
llvm::cl::init(getDefaultAsyncThreadsCount()));
static llvm::cl::opt<bool> EnableSnippets(
"enable-snippets",
llvm::cl::desc(
"Present snippet completions instead of plaintext completions. "
"This also enables code pattern results." /* FIXME: should it? */),
llvm::cl::init(clangd::CodeCompleteOptions().EnableSnippets));
// FIXME: Flags are the wrong mechanism for user preferences.
// We should probably read a dotfile or similar.
static llvm::cl::opt<bool> IncludeIneligibleResults(
@ -237,7 +230,6 @@ int main(int argc, char *argv[]) {
if (EnableIndexBasedCompletion && !YamlSymbolFile.empty())
StaticIdx = BuildStaticIndex(YamlSymbolFile);
clangd::CodeCompleteOptions CCOpts;
CCOpts.EnableSnippets = EnableSnippets;
CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
CCOpts.Limit = LimitCompletionResult;
// Initialize and run ClangdLSPServer.

View File

@ -0,0 +1,43 @@
# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck -strict-whitespace %s
{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"processId": 123,
"rootPath": "clangd",
"capabilities": {
"textDocument": {
"completion": {
"completionItem": {
"snippetSupport": true
}
}
}
},
"trace": "off"
}
}
---
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int func_with_args(int a, int b);\nint main() {\nfunc_with\n}"}}}
---
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":2,"character":7}}}
# CHECK: "id": 1
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": {
# CHECK-NEXT: "isIncomplete": {{.*}}
# CHECK-NEXT: "items": [
# CHECK-NEXT: {
# CHECK-NEXT: "detail": "int",
# CHECK-NEXT: "filterText": "func_with_args",
# CHECK-NEXT: "insertText": "func_with_args(${1:int a}, ${2:int b})",
# CHECK-NEXT: "insertTextFormat": 2,
# CHECK-NEXT: "kind": 3,
# CHECK-NEXT: "label": "func_with_args(int a, int b)",
# CHECK-NEXT: "sortText": "{{.*}}func_with_args"
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: }
---
{"jsonrpc":"2.0","id":4,"method":"shutdown"}